summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadia Barbosa <nadiabarbosa@me.com>2018-09-17 15:45:22 -0700
committerNadia Barbosa <nadiabarbosa@me.com>2018-10-01 16:47:18 -0400
commit53b6b47c4f4408a256ee1fdc8acd37dfc867d117 (patch)
tree1565f14c1b366b0b4e2c8c3b4ae5c3f43aa48298
parent0dff7879f67d446eda57033618f7b082e3716496 (diff)
downloadqtlocation-mapboxgl-53b6b47c4f4408a256ee1fdc8acd37dfc867d117.tar.gz
[ios] Add delegate method to specify the user location annotation’s position
Update method name More API drafting Add deprecation flag Add Swift delegate integration test Update method name and documentation Update deprecation notices Update method name Offset anchor point relative to contentFrame Update docs Only run through switch statement if delegate is unimplemented Account for content inset + refactor logic Adjust edgePaddingForFollowing Fix Swift delegate integration test Set up integration test Set up test location manager . Remove unused file reference from test Return CGPoint value from delegate method within integration test setup Test anchor points Make updateUserLocationAnnotationView public Refactor test
-rw-r--r--platform/ios/Integration Test Harness/Info.plist2
-rw-r--r--platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m26
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.h1
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.m7
-rw-r--r--platform/ios/Integration Tests/MGLTestLocationManager.h10
-rw-r--r--platform/ios/Integration Tests/MGLTestLocationManager.m51
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj7
-rw-r--r--platform/ios/src/MGLMapView.h16
-rw-r--r--platform/ios/src/MGLMapView.mm18
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h11
-rw-r--r--platform/ios/test/MGLMapViewDelegateIntegrationTests.swift2
11 files changed, 143 insertions, 8 deletions
diff --git a/platform/ios/Integration Test Harness/Info.plist b/platform/ios/Integration Test Harness/Info.plist
index 4222ac2dd3..be30bb5cc5 100644
--- a/platform/ios/Integration Test Harness/Info.plist
+++ b/platform/ios/Integration Test Harness/Info.plist
@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>NSLocationWhenInUseUsageDescription</key>
+ <string>Used to run user location tests</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
diff --git a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
index ba63a9eff4..fefb938773 100644
--- a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
+++ b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
@@ -1,6 +1,7 @@
#import "MGLMapViewIntegrationTest.h"
#import "MGLTestUtility.h"
#import "MGLMapAccessibilityElement.h"
+#import "MGLTestLocationManager.h"
@interface MGLMapView (Tests)
- (MGLAnnotationTag)annotationTagAtPoint:(CGPoint)point persistingResults:(BOOL)persist;
@@ -91,6 +92,31 @@
}
}
+- (void)testUserLocationWithOffsetAnchorPoint {
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(37.787357, -122.39899)];
+ MGLTestLocationManager *locationManager = [[MGLTestLocationManager alloc] init];
+ self.mapView.locationManager = locationManager;
+
+ [self.mapView setUserTrackingMode:MGLUserTrackingModeFollow animated:NO];
+ CGRect originalFrame = [self.mapView viewForAnnotation:self.mapView.userLocation].frame;
+
+ // Temporarily disable location tracking so we can save the value of
+ // the originalFrame in memory
+ [self.mapView setUserTrackingMode:MGLUserTrackingModeNone animated:NO];
+
+ CGPoint offset = CGPointMake(20, 20);
+
+ self.mapViewUserLocationAnchorPoint = ^CGPoint (MGLMapView *mapView) {
+ return offset;;
+ };
+
+ [self.mapView setUserTrackingMode:MGLUserTrackingModeFollow animated:NO];
+ CGRect offsetFrame = [self.mapView viewForAnnotation:self.mapView.userLocation].frame;
+
+ XCTAssertEqual(originalFrame.origin.x + offset.x, offsetFrame.origin.x);
+ XCTAssertEqual(originalFrame.origin.y + offset.y, offsetFrame.origin.y);
+}
+
- (void)waitForCollisionDetectionToRun {
XCTAssertNil(self.renderFinishedExpectation, @"Incorrect test setup");
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
index f513df8b20..2f459a5f44 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
@@ -26,6 +26,7 @@
@property (nonatomic) void (^regionWillChange)(MGLMapView *mapView, BOOL animated);
@property (nonatomic) void (^regionIsChanging)(MGLMapView *mapView);
@property (nonatomic) void (^regionDidChange)(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated);
+@property (nonatomic) CGPoint (^mapViewUserLocationAnchorPoint)(MGLMapView *mapView);
// Utility methods
- (NSString*)validAccessToken;
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
index c427a7842f..7153257df5 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
@@ -101,6 +101,13 @@
}
}
+- (CGPoint)mapViewUserLocationAnchorPoint:(MGLMapView *)mapView {
+ if (self.mapViewUserLocationAnchorPoint) {
+ return self.mapViewUserLocationAnchorPoint(mapView);
+ }
+ return CGPointZero;
+}
+
#pragma mark - Utilities
- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout {
diff --git a/platform/ios/Integration Tests/MGLTestLocationManager.h b/platform/ios/Integration Tests/MGLTestLocationManager.h
new file mode 100644
index 0000000000..e0e6f25bb2
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLTestLocationManager.h
@@ -0,0 +1,10 @@
+#import <XCTest/XCTest.h>
+#import <Mapbox/Mapbox.h>
+#import "MGLTestUtility.h"
+
+@interface MGLTestLocationManager : NSObject<MGLLocationManager>
+@end
+
+@interface MGLTestLocationManager()
+
+@end
diff --git a/platform/ios/Integration Tests/MGLTestLocationManager.m b/platform/ios/Integration Tests/MGLTestLocationManager.m
new file mode 100644
index 0000000000..2ec27c08ed
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLTestLocationManager.m
@@ -0,0 +1,51 @@
+#import "MGLTestLocationManager.h"
+
+// Used to supply integration tests with a simulated location manager.
+// Methods that are empty are not used within integration tests and are
+// therefore unimplemented.
+
+@implementation MGLTestLocationManager
+
+@synthesize delegate;
+
+- (instancetype)init
+{
+ if (self = [super init]) {
+ }
+ return self;
+}
+
+- (CLAuthorizationStatus)authorizationStatus { return [CLLocationManager authorizationStatus]; }
+
+- (void)setHeadingOrientation:(CLDeviceOrientation)headingOrientation { }
+
+- (CLDeviceOrientation)headingOrientation { return 90; }
+
+- (void)requestAlwaysAuthorization { }
+
+- (void)requestWhenInUseAuthorization { }
+
+- (void)startUpdatingHeading { }
+
+// Simulate one location update
+- (void)startUpdatingLocation
+{
+ if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {
+ CLLocation *location = [[CLLocation alloc] initWithLatitude:37.787357 longitude:-122.39899];
+ [self.delegate locationManager:self didUpdateLocations:@[location]];
+ }
+}
+
+- (void)stopUpdatingHeading { }
+
+- (void)stopUpdatingLocation { }
+
+- (void)dismissHeadingCalibrationDisplay { }
+
+- (void)dealloc { self.delegate = nil; }
+
+- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { }
+
+- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager { return NO; }
+
+@end
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index d773033658..9cf2c99513 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -14,6 +14,8 @@
071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; };
076171C32139C70900668A35 /* MGLMapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 076171C22139C70900668A35 /* MGLMapViewTests.m */; };
076171C72141A91700668A35 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 076171C62141A91700668A35 /* Settings.bundle */; };
+ 077061D6215D97EF000FEF62 /* simple_route.json in Resources */ = {isa = PBXBuildFile; fileRef = 1F26B6C220E1A351007BCC21 /* simple_route.json */; };
+ 077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */; };
0778DD431F67556700A73B34 /* MGLComputedShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0778DD401F67555F00A73B34 /* MGLComputedShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
0778DD441F67556C00A73B34 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */; };
07D8C6FB1F67560100381808 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */; };
@@ -746,6 +748,8 @@
071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; };
076171C22139C70900668A35 /* MGLMapViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLMapViewTests.m; path = ../../darwin/test/MGLMapViewTests.m; sourceTree = "<group>"; };
076171C62141A91700668A35 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = app/Settings.bundle; sourceTree = SOURCE_ROOT; };
+ 077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTestLocationManager.m; sourceTree = "<group>"; };
+ 077061DB215DA11F000FEF62 /* MGLTestLocationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTestLocationManager.h; sourceTree = "<group>"; };
0778DD401F67555F00A73B34 /* MGLComputedShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLComputedShapeSource.h; sourceTree = "<group>"; };
0778DD411F67555F00A73B34 /* MGLComputedShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLComputedShapeSource.mm; sourceTree = "<group>"; };
07D8C6FD1F67562800381808 /* MGLComputedShapeSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLComputedShapeSourceTests.m; path = ../../darwin/test/MGLComputedShapeSourceTests.m; sourceTree = "<group>"; };
@@ -1374,6 +1378,8 @@
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */,
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */,
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */,
+ 077061DB215DA11F000FEF62 /* MGLTestLocationManager.h */,
+ 077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */,
);
path = "Integration Tests";
sourceTree = "<group>";
@@ -2822,6 +2828,7 @@
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */,
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */,
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */,
+ 077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */,
CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */,
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */,
);
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 02d146edcb..be4ac59c1b 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -416,7 +416,7 @@ MGL_EXPORT IB_DESIGNABLE
transition. If you don’t want to animate the change, use the
`-setUserLocationVerticalAlignment:animated:` method instead.
*/
-@property (nonatomic, assign) MGLAnnotationVerticalAlignment userLocationVerticalAlignment;
+@property (nonatomic, assign) MGLAnnotationVerticalAlignment userLocationVerticalAlignment __attribute__((deprecated("Use -[MGLMapViewDelegate mapViewUserLocationAnchorPoint:] instead.")));
/**
Sets the vertical alignment of the user location annotation within the
@@ -427,7 +427,19 @@ MGL_EXPORT IB_DESIGNABLE
position within the map view. If `NO`, the user location annotation
instantaneously moves to its new position.
*/
-- (void)setUserLocationVerticalAlignment:(MGLAnnotationVerticalAlignment)alignment animated:(BOOL)animated;
+- (void)setUserLocationVerticalAlignment:(MGLAnnotationVerticalAlignment)alignment animated:(BOOL)animated __attribute__((deprecated("Use -[MGLMapViewDelegate mapViewUserLocationAnchorPoint:] instead.")));
+
+/**
+ Updates the position of the user location annotation view by retreiving the user's last
+ known location.
+ */
+- (void)updateUserLocationAnnotationView;
+
+/**
+ Updates the position of the user location annotation view by retreiving the user's last
+ known location with a specified duration.
+*/
+- (void)updateUserLocationAnnotationViewAnimatedWithDuration:(NSTimeInterval)duration;
/**
A Boolean value indicating whether the user location annotation may display a
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index e6ac274b4c..1f5f3c4fd2 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -5280,9 +5280,9 @@ public:
correctPoint.x - CGRectGetMidX(bounds),
correctPoint.y - CGRectGetMidY(bounds));
return UIEdgeInsetsMake(CGRectGetMinY(boundsAroundCorrectPoint) - CGRectGetMinY(bounds),
- self.contentInset.left,
+ CGRectGetMaxX(boundsAroundCorrectPoint) - CGRectGetMaxX(bounds),
CGRectGetMaxY(bounds) - CGRectGetMaxY(boundsAroundCorrectPoint),
- self.contentInset.right);
+ CGRectGetMaxX(bounds) - CGRectGetMaxX(boundsAroundCorrectPoint));
}
/// Returns the edge padding to apply during bifocal course tracking.
@@ -5998,15 +5998,21 @@ public:
/// the overall map view (but respecting the content inset).
- (CGPoint)userLocationAnnotationViewCenter
{
+ if ([self.delegate respondsToSelector:@selector(mapViewUserLocationAnchorPoint:)])
+ {
+ CGPoint anchorPoint = [self.delegate mapViewUserLocationAnchorPoint:self];
+ return CGPointMake(anchorPoint.x + self.contentInset.left, anchorPoint.y + self.contentInset.top);
+ }
+
CGRect contentFrame = UIEdgeInsetsInsetRect(self.contentFrame, self.edgePaddingForFollowingWithCourse);
+
if (CGRectIsEmpty(contentFrame))
{
contentFrame = self.contentFrame;
}
+
CGPoint center = CGPointMake(CGRectGetMidX(contentFrame), CGRectGetMidY(contentFrame));
-
- // When tracking course, it’s more important to see the road ahead, so
- // weight the user dot down towards the bottom.
+
switch (self.userLocationVerticalAlignment) {
case MGLAnnotationVerticalAlignmentCenter:
break;
@@ -6017,7 +6023,7 @@ public:
center.y = CGRectGetMaxY(contentFrame);
break;
}
-
+
return center;
}
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 4bd1a95c9b..fe2a0962ba 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -308,6 +308,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated;
+/**
+ Returns a CGPoint value to offset the user location annotation, relative to the
+ map view’s origin after applying the map view’s content insets.
+
+ This method will offset the user location annotation by the specified
+ X and Y values determined by the CGPoint.
+
+ @param mapView The map view that is tracking the user's location.
+ */
+- (CGPoint)mapViewUserLocationAnchorPoint:(MGLMapView *)mapView;
+
#pragma mark Managing the Appearance of Annotations
/**
diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
index 48673b1d14..4904cb185b 100644
--- a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
+++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift
@@ -92,4 +92,6 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera) -> Bool { return false }
func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera, reason: MGLCameraChangeReason) -> Bool { return false }
+
+ func mapViewUserLocationAnchorPoint(_ mapView: MGLMapView) -> CGPoint { return CGPoint(x: 100, y: 100) }
}