From d876274ad19866c8395c97ef4fd1f31eddf3b23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 6 May 2015 16:38:59 -0700 Subject: [PATCH 01/72] Prevent full-circle spin during animated rotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #1295 made #1199 a lot less common, but it was still possible for the map to do a full 180° when drift-rotating past due-south. With this change, the map is atomically rotated to a bearing in the same cycle as the final bearing. /cc @friedbunny --- src/mbgl/map/transform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index ffe742296..1239f96f5 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -348,6 +348,7 @@ void Transform::_setAngle(double new_angle, const Duration duration) { MapChangeRegionWillChange); final.angle = _normalizeAngle(new_angle, current.angle); + current.angle = _normalizeAngle(current.angle, final.angle); if (duration == Duration::zero()) { current.angle = final.angle; From 2529baa62b509f2c763d5b3f9f5e1e388a45917f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 15:33:28 -0700 Subject: [PATCH 02/72] Grab access token and other app-wide data from Info.plist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That way there’s no ambiguity about when you should call things like `+[MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:]`. In fact, that method is now deprecated because it’s so easy to call in the wrong place. Fixes #1535. --- include/mbgl/ios/MGLAccountManager.h | 2 +- platform/ios/MGLAccountManager.m | 17 ++++++++++++++++- platform/ios/MGLMapboxEvents.m | 4 +++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/mbgl/ios/MGLAccountManager.h b/include/mbgl/ios/MGLAccountManager.h index 7ec4135f1..5c1b2e357 100644 --- a/include/mbgl/ios/MGLAccountManager.h +++ b/include/mbgl/ios/MGLAccountManager.h @@ -21,7 +21,7 @@ /** Certain Mapbox plans require the collection of user metrics. If you aren't using a preference switch in an existing or new `Settings.bundle` in your application, set this value to `YES` to indicate that you are providing a metrics opt-out for users within your app's interface directly. * @param showsOptOut Whether your application's interface provides a user opt-out preference. The default value is `NO`, meaning a `Settings.bundle` is expected for providing a user opt-out preference. */ -+ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut; ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut DEPRECATED_MSG_ATTRIBUTE("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist"); /** Whether in-app user metrics opt-out is configured. If set to the default value of `NO`, a user opt-out preference is expected in a `Settings.bundle` that shows in the application's section within the system Settings app. */ + (BOOL)mapboxMetricsEnabledSettingShownInApp; diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 2e3c0a38e..819dd741d 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -9,11 +9,25 @@ @property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; @property (atomic) NSString *accessToken; ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut; + @end @implementation MGLAccountManager ++ (void)initialize { + if (self == [MGLAccountManager class]) { + // Read initial configuration from Info.plist. + NSBundle *bundle = [NSBundle bundleForClass:self]; + self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; + NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; + if (shownInAppNumber) { + [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; + } + } +} + // Can be called from any thread. // + (instancetype) sharedManager { @@ -25,7 +39,6 @@ void (^setupBlock)() = ^{ dispatch_once(&onceToken, ^{ _sharedManager = [[self alloc] init]; - _sharedManager.mapboxMetricsEnabledSettingShownInApp = NO; }); }; if ( ! [[NSThread currentThread] isMainThread]) { @@ -48,6 +61,8 @@ } + (void) setAccessToken:(NSString *) accessToken { + if ( ! [accessToken length]) return; + [[MGLAccountManager sharedManager] setAccessToken:accessToken]; // Update MGLMapboxEvents diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 2b9d88777..017dceeb3 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -176,8 +176,10 @@ const NSTimeInterval MGLFlushInterval = 60; + (void)initialize { if (self == [MGLMapboxEvents class]) { + NSBundle *bundle = [NSBundle bundleForClass:self]; + NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccountType"]; [[NSUserDefaults standardUserDefaults] registerDefaults:@{ - @"MGLMapboxAccountType": @0, + @"MGLMapboxAccountType": accountTypeNumber ? accountTypeNumber : @0, @"MGLMapboxMetricsEnabled": @YES, }]; } From cbb7112e8c2a79a4777a1e439029686dc3e3547e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 16:08:40 -0700 Subject: [PATCH 03/72] Set up MGLAccountManager without any prodding `MGLAccountManager` is now guaranteed to initialize without the code ever making any mention of it. It also is guaranteed to be set up before `MGLMapboxMetrics` but will definitely cause `MGLMapboxMetrics` to be set up on the main thread if the access token is set in Info.plist. --- platform/ios/MGLAccountManager.m | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 819dd741d..d5b89e9f9 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -16,15 +16,13 @@ @implementation MGLAccountManager -+ (void)initialize { - if (self == [MGLAccountManager class]) { - // Read initial configuration from Info.plist. - NSBundle *bundle = [NSBundle bundleForClass:self]; - self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; - NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; - if (shownInAppNumber) { - [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; - } ++ (void)load { + // Read initial configuration from Info.plist. + NSBundle *bundle = [NSBundle bundleForClass:self]; + self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; + NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; + if (shownInAppNumber) { + [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; } } @@ -63,7 +61,7 @@ + (void) setAccessToken:(NSString *) accessToken { if ( ! [accessToken length]) return; - [[MGLAccountManager sharedManager] setAccessToken:accessToken]; + [MGLAccountManager sharedManager].accessToken = accessToken; // Update MGLMapboxEvents // NOTE: This is (likely) the initial setup of MGLMapboxEvents From 164ff72297a0b57c42cc5dc1299e6b7f1dd13db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 16:33:40 -0700 Subject: [PATCH 04/72] Fall back on MGLAccountManager access token Makes IB designables aware of access tokens set via Info.plist. --- platform/ios/MGLMapView.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index c928dd6ae..4be5d20d2 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -153,7 +153,8 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) - (NSString *)accessToken { - return @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty; + NSString *accessToken = @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty; + return accessToken ? accessToken : [MGLAccountManager accessToken]; } - (void)setAccessToken:(NSString *)accessToken @@ -2559,7 +2560,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) // More explanation UILabel *explanationLabel2 = [[UILabel alloc] init]; - explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector."; + explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector or in an MGLMapboxAccessToken entry in the Info.plist file."; explanationLabel2.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; explanationLabel2.numberOfLines = 0; explanationLabel2.translatesAutoresizingMaskIntoConstraints = NO; From 0ad76c95d20f7ef7b7ef712d8edb8c54219880e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 22:33:03 -0700 Subject: [PATCH 05/72] Obsoleted +setMapboxMetricsEnabledSettingShownInApp: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made `+[MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:]` unavailable, with a message explaining what to do instead. Removed a commented-out call to that method. Only the environment for an access token if one hasn’t already been set in Info.plist. --- include/mbgl/ios/MGLAccountManager.h | 2 +- ios/app/MBXAppDelegate.m | 32 +++++++++++++--------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/mbgl/ios/MGLAccountManager.h b/include/mbgl/ios/MGLAccountManager.h index 5c1b2e357..6b127543e 100644 --- a/include/mbgl/ios/MGLAccountManager.h +++ b/include/mbgl/ios/MGLAccountManager.h @@ -21,7 +21,7 @@ /** Certain Mapbox plans require the collection of user metrics. If you aren't using a preference switch in an existing or new `Settings.bundle` in your application, set this value to `YES` to indicate that you are providing a metrics opt-out for users within your app's interface directly. * @param showsOptOut Whether your application's interface provides a user opt-out preference. The default value is `NO`, meaning a `Settings.bundle` is expected for providing a user opt-out preference. */ -+ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut DEPRECATED_MSG_ATTRIBUTE("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist"); ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut __attribute__((unavailable("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist."))); /** Whether in-app user metrics opt-out is configured. If set to the default value of `NO`, a user opt-out preference is expected in a `Settings.bundle` that shows in the application's section within the system Settings app. */ + (BOOL)mapboxMetricsEnabledSettingShownInApp; diff --git a/ios/app/MBXAppDelegate.m b/ios/app/MBXAppDelegate.m index ce699ce69..39868b174 100644 --- a/ios/app/MBXAppDelegate.m +++ b/ios/app/MBXAppDelegate.m @@ -8,24 +8,22 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Set Access Token - NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; - if (accessToken) { - // Store to preferences so that we can launch the app later on without having to specify - // token. - [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"access_token"]; - } else { - // Try to retrieve from preferences, maybe we've stored them there previously and can reuse - // the token. - accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"]; + // Set access token, unless MGLAccountManager already read it in from Info.plist. + if ( ! [MGLAccountManager accessToken]) { + NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; + if (accessToken) { + // Store to preferences so that we can launch the app later on without having to specify + // token. + [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"access_token"]; + } else { + // Try to retrieve from preferences, maybe we've stored them there previously and can reuse + // the token. + accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"]; + } + if ( ! accessToken) NSLog(@"No access token set. Mapbox vector tiles won't work."); + + [MGLAccountManager setAccessToken:accessToken]; } - if ( ! accessToken) NSLog(@"No access token set. Mapbox vector tiles won't work."); - - // Signal To SDK That Opt Out Is In App UI -// [MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:YES]; - - // Start Mapbox GL SDK - [MGLAccountManager setAccessToken:accessToken]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[MBXViewController new]]; From a04703e2d59ccedf32ef9bbd22169640a5aeec50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 14 May 2015 00:38:52 -0700 Subject: [PATCH 06/72] Updated Metrics in-app opt-out assertion The message referred to `+[MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:]`, which is no longer available. --- platform/ios/MGLMapboxEvents.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 017dceeb3..44972395d 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -215,7 +215,7 @@ const NSTimeInterval MGLFlushInterval = 60; } } - NSAssert(defaultEnabledValue, @"End users must be able to opt out of Metrics in your app, either inside Settings (via Settings.bundle) or inside this app. If you implement the opt-out control inside this app, disable this assertion by setting [MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:YES] before the app initializes any Mapbox GL classes."); + NSAssert(defaultEnabledValue, @"End users must be able to opt out of Metrics in your app, either inside Settings (via Settings.bundle) or inside this app. If you implement the opt-out control inside this app, disable this assertion by setting MGLMapboxMetricsEnabledSettingShownInApp to YES in Info.plist."); [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"MGLMapboxMetricsEnabled": defaultEnabledValue, }]; From 00b2e13b64afd7eb0fde1e60db7ca75cafe85469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 14 May 2015 14:49:26 -0700 Subject: [PATCH 07/72] =?UTF-8?q?mapID=20=E2=86=92=20styleID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecated `-mapID` and `-setMapID:` to accurately reflect the APIs the ID is used for. Marked the property unavailable but reimplemented its getter and setter to assert with helpful messages. Fixes #1500. --- include/mbgl/ios/MGLMapView+IBAdditions.h | 2 +- include/mbgl/ios/MGLMapView.h | 7 +++--- platform/ios/MGLMapView.mm | 26 +++++++++++++---------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/mbgl/ios/MGLMapView+IBAdditions.h b/include/mbgl/ios/MGLMapView+IBAdditions.h index df9a19a6b..0f1d2b2f8 100644 --- a/include/mbgl/ios/MGLMapView+IBAdditions.h +++ b/include/mbgl/ios/MGLMapView+IBAdditions.h @@ -9,7 +9,7 @@ // MGLMapView+IBAdditions.h, due to ASCII sort order. @property (nonatomic) IBInspectable NSString *accessToken; -@property (nonatomic) IBInspectable NSString *mapID; +@property (nonatomic) IBInspectable NSString *styleID; // Convenience properties related to the initial viewport. These properties // are not meant to be used outside of Interface Builder. latitude and longitude diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 9d7b5c901..50174e31c 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -162,12 +162,13 @@ IB_DESIGNABLE /** @name Styling the Map */ -/** Mapbox map ID of the style currently displayed in the receiver, or `nil` if the style does not have a map ID. +/** Mapbox ID of the style currently displayed in the receiver, or `nil` if the style does not have an ID. * -* The style may lack a map ID if it is located at an HTTP, HTTPS, or local file URL. Use `styleURL` to get the URL in these cases. +* The style may lack an ID if it is located at an HTTP, HTTPS, or local file URL. Use `styleURL` to get the URL in these cases. * * To display the default style, set this property to `nil`. */ -@property (nonatomic) NSString *mapID; +@property (nonatomic) NSString *styleID; +@property (nonatomic) NSString *mapID __attribute__((unavailable("Use styleID."))); /** Returns the URLs to the styles bundled with the library. */ - (NSArray *)bundledStyleURLs; diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index ff31ec9e1..b488d01f6 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -162,7 +162,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) + (NSSet *)keyPathsForValuesAffectingStyleURL { - return [NSSet setWithObjects:@"mapID", @"accessToken", nil]; + return [NSSet setWithObjects:@"styleID", @"accessToken", nil]; } - (NSURL *)styleURL @@ -1543,27 +1543,31 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) return [NSArray arrayWithArray:_bundledStyleURLs]; } -+ (NSSet *)keyPathsForValuesAffectingMapID ++ (NSSet *)keyPathsForValuesAffectingStyleID { return [NSSet setWithObjects:@"styleURL", @"accessToken", nil]; } -- (NSString *)mapID +- (NSString *)styleID { NSURL *styleURL = self.styleURL; return [styleURL.scheme isEqualToString:@"mapbox"] ? styleURL.host.mgl_stringOrNilIfEmpty : nil; } +- (void)setStyleID:(NSString *)styleID +{ + self.styleURL = styleID ? [NSURL URLWithString:[NSString stringWithFormat:@"mapbox://%@", styleID]] : nil; +} + +- (NSString *)mapID +{ + NSAssert(NO, @"-[MGLMapView mapID] has been renamed -[MGLMapView styleID]."); + return nil; +} + - (void)setMapID:(NSString *)mapID { - if (mapID) - { - self.styleURL = [NSURL URLWithString:[NSString stringWithFormat:@"mapbox://%@", mapID]]; - } - else - { - self.styleURL = nil; - } + NSAssert(NO, @"-[MGLMapView setMapID:] has been renamed -[MGLMapView setStyleID:].\n\nIf you previously set this map ID in a storyboard inspectable, select the MGLMapView in Interface Builder and delete the “mapID” entry from the User Defined Runtime Attributes section of the Identity inspector. Then go to the Attributes inspector and enter “%@” into the “Style ID” field.", mapID); } - (NSArray *)styleClasses From a87c58fcb186a4958e7aecd517f55d5e328e95b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 19 May 2015 15:58:14 +0200 Subject: [PATCH 08/72] fix Travis stage name --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f08aa8149..1ac66b386 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,7 @@ script: after_failure: - "[ -f ./scripts/${FLAVOR}/after_failure.sh ] && ./scripts/${FLAVOR}/after_failure.sh" -after_failure: +after_script: - "[ -f ./scripts/${FLAVOR}/after_script.sh ] && ./scripts/${FLAVOR}/after_script.sh" notifications: From ab3105aac9cfd0e3c376bc50271ece0ad59232e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 19 May 2015 15:01:33 +0200 Subject: [PATCH 09/72] don't mark the glyphs as parsed until we've actually parsed them --- src/mbgl/text/glyph_store.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 853191218..10723af1a 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -167,7 +167,6 @@ GlyphPBF::GlyphPBF(const std::string& glyphURL, // parse the data we received. We are not doing this here since this callback is being // called from another (unknown) thread. data = res.data; - parsed = true; callback(this); } }); @@ -231,6 +230,8 @@ void GlyphPBF::parse(FontStack &stack) { } data.clear(); + + parsed = true; } bool GlyphPBF::isParsed() const { From b0c89e7f44a9a917e4d40ab3b7a8f57465ccdddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 19 May 2015 15:04:02 +0200 Subject: [PATCH 10/72] extend the FontStack lock to returned values --- src/mbgl/renderer/symbol_bucket.cpp | 4 ++-- src/mbgl/text/glyph_store.cpp | 8 ++++---- src/mbgl/text/glyph_store.hpp | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 4d957a1e5..d984752f1 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -190,7 +190,7 @@ void SymbolBucket::addFeatures(uintptr_t tileUID, if (layout.text.justify == TextJustifyType::Right) justify = 1; else if (layout.text.justify == TextJustifyType::Left) justify = 0; - auto* fontStack = glyphStore.getFontStack(layout.text.font); + auto fontStack = glyphStore.getFontStack(layout.text.font); for (const auto& feature : features) { if (!feature.geometry.size()) continue; @@ -214,7 +214,7 @@ void SymbolBucket::addFeatures(uintptr_t tileUID, // Add the glyphs we need for this label to the glyph atlas. if (shaping.size()) { - glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, *fontStack, face); + glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, **fontStack, face); } } diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 10723af1a..031720325 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -297,15 +297,15 @@ FontStack* GlyphStore::createFontStack(const std::string &fontStack) { return stack_it->second.get(); } -FontStack* GlyphStore::getFontStack(const std::string &fontStack) { - std::lock_guard lock(stacksMutex); +util::exclusive GlyphStore::getFontStack(const std::string &fontStack) { + auto lock = util::make_unique>(stacksMutex); const auto& stack_it = stacks.find(fontStack); if (stack_it == stacks.end()) { - return nullptr; + return { nullptr, nullptr }; } - return stack_it->second.get(); + return { stack_it->second.get(), std::move(lock) }; } void GlyphStore::setObserver(Observer* observer_) { diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index efa848dd0..a42130855 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,7 @@ public: // GlyphRanges are already available, and thus, no request is performed. bool requestGlyphRangesIfNeeded(const std::string &fontStack, const std::set &glyphRanges); - FontStack* getFontStack(const std::string &fontStack); + util::exclusive getFontStack(const std::string &fontStack); void setURL(const std::string &url); From bcf66b74491be81e1cd6bb6bf9fb489b7a36f79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 19 May 2015 15:13:05 +0200 Subject: [PATCH 11/72] only return locked FontStack objects --- include/mbgl/util/exclusive.hpp | 30 ++++++++++++++++++++++++++++++ src/mbgl/text/glyph_store.cpp | 24 +++++++++--------------- src/mbgl/text/glyph_store.hpp | 5 +---- 3 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 include/mbgl/util/exclusive.hpp diff --git a/include/mbgl/util/exclusive.hpp b/include/mbgl/util/exclusive.hpp new file mode 100644 index 000000000..bb3395996 --- /dev/null +++ b/include/mbgl/util/exclusive.hpp @@ -0,0 +1,30 @@ +#ifndef MBGL_UTIL_EXCLUSIVE +#define MBGL_UTIL_EXCLUSIVE + +#include +#include + + +namespace mbgl { +namespace util { + +template +class exclusive { +public: + inline exclusive(T* val, std::unique_ptr> mtx) : ptr(val), lock(std::move(mtx)) {} + + inline T* operator->() { return ptr; } + inline const T* operator->() const { return ptr; } + inline T* operator*() { return ptr; } + inline const T* operator*() const { return ptr; } + +private: + T *ptr; + std::unique_ptr> lock; +}; + + +} // end namespace util +} // end namespace mbgl + +#endif diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 031720325..4ee853b1e 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -20,19 +20,16 @@ namespace mbgl { void FontStack::insert(uint32_t id, const SDFGlyph &glyph) { - std::lock_guard lock(mtx); metrics.emplace(id, glyph.metrics); bitmaps.emplace(id, glyph.bitmap); sdfs.emplace(id, glyph); } const std::map &FontStack::getMetrics() const { - std::lock_guard lock(mtx); return metrics; } const std::map &FontStack::getSDFs() const { - std::lock_guard lock(mtx); return sdfs; } @@ -40,8 +37,6 @@ const Shaping FontStack::getShaping(const std::u32string &string, const float ma const float lineHeight, const float horizontalAlign, const float verticalAlign, const float justify, const float spacing, const vec2 &translate) const { - std::lock_guard lock(mtx); - Shaping shaping; int32_t x = std::round(translate.x * 24); // one em @@ -179,8 +174,6 @@ GlyphPBF::~GlyphPBF() { } void GlyphPBF::parse(FontStack &stack) { - std::lock_guard lock(mtx); - if (!data.size()) { // If there is no data, this means we either haven't received any data, or // we have already parsed the data. @@ -253,7 +246,7 @@ void GlyphStore::setURL(const std::string &url) { glyphURL = url; } -bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStack, +bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStackName, const std::set& glyphRanges) { bool requestIsNeeded = false; @@ -261,18 +254,19 @@ bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStack, return requestIsNeeded; } - auto callback = [this, fontStack](GlyphPBF* glyph) { - glyph->parse(*createFontStack(fontStack)); + auto callback = [this, fontStackName](GlyphPBF* glyph) { + auto fontStack = createFontStack(fontStackName); + glyph->parse(**fontStack); asyncEmitGlyphRangeLoaded->send(); }; std::lock_guard lock(rangesMutex); - auto& rangeSets = ranges[fontStack]; + auto& rangeSets = ranges[fontStackName]; for (const auto& range : glyphRanges) { const auto& rangeSets_it = rangeSets.find(range); if (rangeSets_it == rangeSets.end()) { - auto glyph = util::make_unique(glyphURL, fontStack, range, env, callback); + auto glyph = util::make_unique(glyphURL, fontStackName, range, env, callback); rangeSets.emplace(range, std::move(glyph)); requestIsNeeded = true; continue; @@ -286,15 +280,15 @@ bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStack, return requestIsNeeded; } -FontStack* GlyphStore::createFontStack(const std::string &fontStack) { - std::lock_guard lock(stacksMutex); +util::exclusive GlyphStore::createFontStack(const std::string &fontStack) { + auto lock = util::make_unique>(stacksMutex); auto stack_it = stacks.find(fontStack); if (stack_it == stacks.end()) { stack_it = stacks.emplace(fontStack, util::make_unique()).first; } - return stack_it->second.get(); + return { stack_it->second.get(), std::move(lock) }; } util::exclusive GlyphStore::getFontStack(const std::string &fontStack) { diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index a42130855..e13ed1f1d 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -54,7 +54,6 @@ private: std::map bitmaps; std::map metrics; std::map sdfs; - mutable std::mutex mtx; }; class GlyphPBF { @@ -82,8 +81,6 @@ private: Environment& env; Request* req = nullptr; - - mutable std::mutex mtx; }; // Manages Glyphrange PBF loading. @@ -114,7 +111,7 @@ public: private: void emitGlyphRangeLoaded(); - FontStack* createFontStack(const std::string &fontStack); + util::exclusive createFontStack(const std::string &fontStack); std::string glyphURL; Environment &env; From d7bd429619eb5ec2da30dfd2ce3ab669834e51c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 19 May 2015 17:36:32 +0200 Subject: [PATCH 12/72] bump test suite --- test/suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/suite b/test/suite index d4fb34452..91a58547f 160000 --- a/test/suite +++ b/test/suite @@ -1 +1 @@ -Subproject commit d4fb3445252aa7d0666bf563634d2007cb573c03 +Subproject commit 91a58547f3bfc7ead367e1548605564d1131d44c From 03d5e2da80111e225c2478286b60dd4e9b7ec527 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 19 May 2015 09:52:01 -0400 Subject: [PATCH 13/72] port sprite atlas pollution fix fixes #1398 js: 212760981493460b438f1cc117001825773fad91 https://github.com/mapbox/mapbox-gl-js/pull/1195 The sprite atlas already had two empty pixels between each each icon. But the icon's real boundary isn't used for drawing. Drawing uses an icon's box rounded up to the nearest multiple of four. Sometimes this rounded boundary was directly on the edge of another icon. When the icon was sampled with linear interpolation it's edge would get polluted with values from the other icon. This commit shifts all icons and glyphs by 1px so that there is padding on all sides of the box being drawn. The quads used for drawing are shifted in the opposite direction by 1px to compensate for this. --- src/mbgl/geometry/glyph_atlas.cpp | 7 ++++--- src/mbgl/geometry/sprite_atlas.cpp | 12 ++++++++---- src/mbgl/text/placement.cpp | 8 +++++--- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp index bb230e4ef..02271b9c7 100644 --- a/src/mbgl/geometry/glyph_atlas.cpp +++ b/src/mbgl/geometry/glyph_atlas.cpp @@ -69,8 +69,9 @@ Rect GlyphAtlas::addGlyph(uintptr_t tileUID, uint16_t buffered_height = glyph.metrics.height + buffer * 2; // Add a 1px border around every image. - uint16_t pack_width = buffered_width; - uint16_t pack_height = buffered_height; + const uint16_t padding = 1; + uint16_t pack_width = buffered_width + 2 * padding; + uint16_t pack_height = buffered_height + 2 * padding; // Increase to next number divisible by 4, but at least 1. // This is so we can scale down the texture coordinates and pack them @@ -92,7 +93,7 @@ Rect GlyphAtlas::addGlyph(uintptr_t tileUID, // Copy the bitmap const uint8_t* source = reinterpret_cast(glyph.bitmap.data()); for (uint32_t y = 0; y < buffered_height; y++) { - uint32_t y1 = width * (rect.y + y) + rect.x; + uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding; uint32_t y2 = buffered_width * y; for (uint32_t x = 0; x < buffered_width; x++) { data[y1 + x] = source[y2 + x]; diff --git a/src/mbgl/geometry/sprite_atlas.cpp b/src/mbgl/geometry/sprite_atlas.cpp index 5d47793cf..4e05c94ad 100644 --- a/src/mbgl/geometry/sprite_atlas.cpp +++ b/src/mbgl/geometry/sprite_atlas.cpp @@ -127,10 +127,12 @@ SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, bool repea rect.h = pos.height / pos.pixelRatio; } + const float padding = 1; + return SpriteAtlasPosition { {{ float(rect.w), float(rect.h) }}, - {{ float(rect.x) / width, float(rect.y) / height }}, - {{ float(rect.x + rect.w) / width, float(rect.y + rect.h) / height }} + {{ float(rect.x + padding) / width, float(rect.y + padding) / height }}, + {{ float(rect.x + padding + rect.w) / width, float(rect.y + padding + rect.h) / height }} }; } @@ -151,12 +153,14 @@ void SpriteAtlas::copy(const Rect& dst, const SpritePosition& src, co const vec2 srcSize { sprite->raster->getWidth(), sprite->raster->getHeight() }; const Rect srcPos { src.x, src.y, src.width, src.height }; + const int offset = 1; + allocate(); uint32_t *const dstData = data.get(); const vec2 dstSize { static_cast(width * pixelRatio), static_cast(height * pixelRatio) }; - const Rect dstPos { static_cast(dst.x * pixelRatio), - static_cast(dst.y * pixelRatio), + const Rect dstPos { static_cast((offset + dst.x) * pixelRatio), + static_cast((offset + dst.y) * pixelRatio), static_cast(dst.originalW * pixelRatio), static_cast(dst.originalH * pixelRatio) }; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index bee3a073e..6c24d26fd 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -135,11 +135,12 @@ GlyphBox getMergedBoxes(const GlyphBoxes &glyphs, const Anchor &anchor) { Placement Placement::getIcon(Anchor &anchor, const Rect &image, float boxScale, const std::vector &line, const StyleLayoutSymbol &layout) { + const float padding = 1.0f; const float dx = layout.icon.offset[0]; const float dy = layout.icon.offset[1]; - float x1 = dx - image.originalW / 2.0f; + float x1 = dx - image.originalW / 2.0f - padding; float x2 = x1 + image.w; - float y1 = dy - image.originalH / 2.0f; + float y1 = dy - image.originalH / 2.0f - padding; float y2 = y1 + image.h; vec2 tl{x1, y1}; @@ -212,7 +213,8 @@ Placement Placement::getGlyphs(Anchor &anchor, const vec2 &origin, const Placement placement; - const uint32_t buffer = 3; + const uint32_t glyphPadding = 1; + const uint32_t buffer = 3 + glyphPadding; for (const auto& shape : shaping) { auto face_it = face.find(shape.glyph); From bd4fca2ec3f7a2f23e03f6fc36e7affb6c6ca292 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 19 May 2015 10:39:29 -0700 Subject: [PATCH 14/72] Update test suite --- test/suite | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/suite b/test/suite index 91a58547f..aeead7e03 160000 --- a/test/suite +++ b/test/suite @@ -1 +1 @@ -Subproject commit 91a58547f3bfc7ead367e1548605564d1131d44c +Subproject commit aeead7e030747c7a262bbba69522c6b39b0b9e35 From ec4cd494cbec94dc5a7c18378897809c8efa0c9b Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Tue, 19 May 2015 14:23:21 -0500 Subject: [PATCH 15/72] #1596 - Adding mapbox.com checking to http requests --- platform/darwin/http_request_nsurl.mm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm index 5ab4e1b43..85d5bffb0 100644 --- a/platform/darwin/http_request_nsurl.mm +++ b/platform/darwin/http_request_nsurl.mm @@ -154,13 +154,15 @@ void HTTPRequest::start() { @autoreleasepool { NSMutableString *url = [NSMutableString stringWithString:@(resource.url.c_str())]; - if ([[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { - if ([url rangeOfString:@"?"].location == NSNotFound) { - [url appendString:@"?"]; - } else { - [url appendString:@"&"]; + if ([url rangeOfString:@"mapbox.com"].location != NSNotFound) { + if ([[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { + if ([url rangeOfString:@"?"].location == NSNotFound) { + [url appendString:@"?"]; + } else { + [url appendString:@"&"]; + } + [url appendString:@"events=true"]; } - [url appendString:@"events=true"]; } NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; From 90b70180c53c2945c10b9520f9e6aa5f4f697ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 19 May 2015 13:44:29 -0700 Subject: [PATCH 16/72] Compare hostname for adding events=true ref #1596, #1599 --- platform/darwin/http_request_nsurl.mm | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm index 85d5bffb0..bdae9ce51 100644 --- a/platform/darwin/http_request_nsurl.mm +++ b/platform/darwin/http_request_nsurl.mm @@ -153,19 +153,16 @@ void HTTPRequest::start() { @autoreleasepool { - NSMutableString *url = [NSMutableString stringWithString:@(resource.url.c_str())]; - if ([url rangeOfString:@"mapbox.com"].location != NSNotFound) { + NSURL *url = [NSURL URLWithString:@(resource.url.c_str())]; + if ([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"]) { if ([[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { - if ([url rangeOfString:@"?"].location == NSNotFound) { - [url appendString:@"?"]; - } else { - [url appendString:@"&"]; - } - [url appendString:@"events=true"]; + NSString *absoluteString = [url.absoluteString stringByAppendingFormat: + (url.query ? @"&%@" : @"?%@"), @"events=true"]; + url = [NSURL URLWithString:absoluteString]; } } - NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; + NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; if (existingResponse) { if (!existingResponse->etag.empty()) { [req addValue:@(existingResponse->etag.c_str()) forHTTPHeaderField:@"If-None-Match"]; From 52670f05601e35804e79f1ee197f2042a9c94a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 19 May 2015 14:31:30 -0700 Subject: [PATCH 17/72] Cache account type user default --- platform/darwin/http_request_nsurl.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm index bdae9ce51..ef88469b4 100644 --- a/platform/darwin/http_request_nsurl.mm +++ b/platform/darwin/http_request_nsurl.mm @@ -91,6 +91,7 @@ public: NSURLSession *session = nil; NSString *userAgent = nil; + NSInteger accountType = 0; }; HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) { @@ -107,6 +108,8 @@ HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) { // Write user agent string userAgent = @"MapboxGL"; + + accountType = [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"]; } } @@ -155,7 +158,7 @@ void HTTPRequest::start() { NSURL *url = [NSURL URLWithString:@(resource.url.c_str())]; if ([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"]) { - if ([[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { + if (context->accountType == 0) { NSString *absoluteString = [url.absoluteString stringByAppendingFormat: (url.query ? @"&%@" : @"?%@"), @"events=true"]; url = [NSURL URLWithString:absoluteString]; From d474f35371b12d95e2a732d61d1d9f1d9a3f322c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Tue, 19 May 2015 14:33:19 -0700 Subject: [PATCH 18/72] Check account type before comparing hostname --- platform/darwin/http_request_nsurl.mm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm index ef88469b4..ad16a69ac 100644 --- a/platform/darwin/http_request_nsurl.mm +++ b/platform/darwin/http_request_nsurl.mm @@ -157,12 +157,11 @@ void HTTPRequest::start() { @autoreleasepool { NSURL *url = [NSURL URLWithString:@(resource.url.c_str())]; - if ([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"]) { - if (context->accountType == 0) { - NSString *absoluteString = [url.absoluteString stringByAppendingFormat: - (url.query ? @"&%@" : @"?%@"), @"events=true"]; - url = [NSURL URLWithString:absoluteString]; - } + if (context->accountType == 0 && + ([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"])) { + NSString *absoluteString = [url.absoluteString stringByAppendingFormat: + (url.query ? @"&%@" : @"?%@"), @"events=true"]; + url = [NSURL URLWithString:absoluteString]; } NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; From f3d7212137021860b653a6e56fab4677407c68fb Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Tue, 19 May 2015 17:02:54 -0500 Subject: [PATCH 19/72] #1595 - Adding App User count event to be triggered and immediately sent when Access Token is set. --- platform/ios/MGLAccountManager.m | 3 +++ platform/ios/MGLMapboxEvents.h | 1 + platform/ios/MGLMapboxEvents.m | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index a49433777..e0999ba29 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -53,6 +53,9 @@ // Update MGLMapboxEvents // NOTE: This is (likely) the initial setup of MGLMapboxEvents [MGLMapboxEvents sharedManager]; + + // Count App Users + [MGLMapboxEvents pushEvent:MGLEventTypeAppUserCount withAttributes:nil]; } + (NSString *) accessToken { diff --git a/platform/ios/MGLMapboxEvents.h b/platform/ios/MGLMapboxEvents.h index 94aa8be78..174c35514 100644 --- a/platform/ios/MGLMapboxEvents.h +++ b/platform/ios/MGLMapboxEvents.h @@ -1,5 +1,6 @@ #import +extern NSString *const MGLEventTypeAppUserCount; extern NSString *const MGLEventTypeMapLoad; extern NSString *const MGLEventTypeMapTap; extern NSString *const MGLEventTypeMapDragEnd; diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 98bfe21cf..2d41bc240 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -16,6 +16,7 @@ static NSString *const MGLMapboxEventsUserAgent = @"MapboxEventsiOS/1.0"; static NSString *MGLMapboxEventsAPIBase = @"https://api.tiles.mapbox.com"; +NSString *const MGLEventTypeAppUserCount = @"appUserCount"; NSString *const MGLEventTypeMapLoad = @"map.load"; NSString *const MGLEventTypeMapTap = @"map.click"; NSString *const MGLEventTypeMapDragEnd = @"map.dragend"; @@ -481,7 +482,7 @@ const NSTimeInterval MGLFlushInterval = 60; [_eventQueue addObject:finalEvent]; // Has Flush Limit Been Reached? - if (_eventQueue.count >= MGLMaximumEventsPerFlush) { + if (_eventQueue.count >= MGLMaximumEventsPerFlush || [MGLEventTypeAppUserCount isEqualToString:event]) { [strongSelf flush]; } else if (_eventQueue.count == 1) { // If this is first new event on queue start timer, From 58b967605aa882f93d0db220cae29a49444cc842 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 May 2015 11:32:57 -0500 Subject: [PATCH 20/72] Implementing suggestions to tighten up MGLAccountManager and rename MGLEventTypeUserCount to MGLEventTypeAppUserTurnstile --- platform/ios/MGLAccountManager.m | 8 +++----- platform/ios/MGLMapboxEvents.h | 2 +- platform/ios/MGLMapboxEvents.m | 5 +++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index e0999ba29..1a9bbe47a 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -51,11 +51,9 @@ [[MGLAccountManager sharedManager] setAccessToken:accessToken]; // Update MGLMapboxEvents - // NOTE: This is (likely) the initial setup of MGLMapboxEvents - [MGLMapboxEvents sharedManager]; - - // Count App Users - [MGLMapboxEvents pushEvent:MGLEventTypeAppUserCount withAttributes:nil]; + // NOTE: This is (likely) the initial setup of MGLMapboxEvents (via implicit call to +[MGLMapboxEvents sharedManager]) + // Turn the Mapbox Turnstile to Count App Users + [MGLMapboxEvents pushEvent:MGLEventTypeAppUserTurnstile withAttributes:nil]; } + (NSString *) accessToken { diff --git a/platform/ios/MGLMapboxEvents.h b/platform/ios/MGLMapboxEvents.h index 174c35514..00de64a8b 100644 --- a/platform/ios/MGLMapboxEvents.h +++ b/platform/ios/MGLMapboxEvents.h @@ -1,6 +1,6 @@ #import -extern NSString *const MGLEventTypeAppUserCount; +extern NSString *const MGLEventTypeAppUserTurnstile; extern NSString *const MGLEventTypeMapLoad; extern NSString *const MGLEventTypeMapTap; extern NSString *const MGLEventTypeMapDragEnd; diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 2d41bc240..002e38d9d 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -16,7 +16,7 @@ static NSString *const MGLMapboxEventsUserAgent = @"MapboxEventsiOS/1.0"; static NSString *MGLMapboxEventsAPIBase = @"https://api.tiles.mapbox.com"; -NSString *const MGLEventTypeAppUserCount = @"appUserCount"; +NSString *const MGLEventTypeAppUserTurnstile = @"appUserTurnstile"; NSString *const MGLEventTypeMapLoad = @"map.load"; NSString *const MGLEventTypeMapTap = @"map.click"; NSString *const MGLEventTypeMapDragEnd = @"map.dragend"; @@ -316,6 +316,7 @@ const NSTimeInterval MGLFlushInterval = 60; [[MGLMapboxEvents sharedManager] validate]; } +// Used to determine if Mapbox Metrics should be collected at any given point in time - (void)validate { MGLAssertIsMainThread(); BOOL enabledInSettings = [[self class] isEnabled]; @@ -482,7 +483,7 @@ const NSTimeInterval MGLFlushInterval = 60; [_eventQueue addObject:finalEvent]; // Has Flush Limit Been Reached? - if (_eventQueue.count >= MGLMaximumEventsPerFlush || [MGLEventTypeAppUserCount isEqualToString:event]) { + if (_eventQueue.count >= MGLMaximumEventsPerFlush || [MGLEventTypeAppUserTurnstile isEqualToString:event]) { [strongSelf flush]; } else if (_eventQueue.count == 1) { // If this is first new event on queue start timer, From a5bd2fa3c66991ff31ba5d4091eb8400f6fc4397 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 May 2015 12:31:20 -0500 Subject: [PATCH 21/72] #1595 - Adding exception so that Turnstile event will always be sent in --- platform/ios/MGLMapboxEvents.m | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 002e38d9d..364a05180 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -432,9 +432,25 @@ const NSTimeInterval MGLFlushInterval = 60; __weak MGLMapboxEvents *weakSelf = self; dispatch_async(_serialQueue, ^{ + + if ([MGLEventTypeAppUserTurnstile isEqualToString:event]) { + // Build only IDFV event + NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + NSDictionary *vevt = @{@"vendorId": vid}; + + // Add to Queue + [_eventQueue addObject:vevt]; + + // Flush + [MGLMapboxEvents flush]; + + return; + } + MGLMapboxEvents *strongSelf = weakSelf; + if ( ! strongSelf) return; - + // Metrics Collection Has Been Paused if (_paused) { return; From 9a57464f823b36dc0c7b0db75f742a40513ffc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 20 May 2015 10:45:26 -0700 Subject: [PATCH 22/72] Removed accessToken from MGLMapView public API With helpful instructions for migrating to Info.plist or the `MGLAccountManager` API. --- include/mbgl/ios/MGLMapView.h | 27 +++++++++++---------------- platform/ios/MGLMapView.mm | 28 ++++++++++++---------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 9d7b5c901..2d6589bf0 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -20,30 +20,25 @@ IB_DESIGNABLE /** @name Initializing a Map View */ -/** Initialize a map view with the default style, given frame, and access token set in MapboxGL singleton. -* @param frame The frame with which to initialize the map view. -* @return An initialized map view, or `nil` if the map view was unable to be initialized. */ +/** Initializes and returns a newly allocated map view with the specified frame and the default style. +* @param frame The frame for the view, measured in points. +* @return An initialized map view or `nil` if the map view couldn’t be created. */ - (instancetype)initWithFrame:(CGRect)frame; +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken __attribute__((unavailable("Use -initWithFrame:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); -/** Initialize a map view with the default style and a given frame and access token. -* @param frame The frame with which to initialize the map view. -* @param accessToken A Mapbox API access token. -* @return An initialized map view, or `nil` if the map view was unable to be initialized. */ -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken; - -/** Initialize a map view with a given frame, access token, and style URL. - * @param frame The frame with which to initialize the map view. - * @param accessToken A Mapbox API access token. - * @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://`). - * @return An initialized map view, or `nil` if the map view was unable to be initialized. */ -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL; +/** Initializes and returns a newly allocated map view with the specified frame and style URL. +* @param frame The frame for the view, measured in points. +* @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://`). +* @return An initialized map view or `nil` if the map view couldn’t be created. */ +- (instancetype)initWithFrame:(CGRect)frame styleURL:(NSURL *)styleURL; +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL __attribute__((unavailable("Use -initWithFrame:styleURL:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); #pragma mark - Authorizing Access /** @name Authorizing Access */ /** Mapbox API access token for the map view. */ -@property (nonatomic) NSString *accessToken; +@property (nonatomic) NSString *accessToken __attribute__((unavailable("Use +[MGLAccountManager accessToken] and +[MGLAccountManager setAccessToken:]."))); #pragma mark - Managing Constraints diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 4be5d20d2..cb89c58d4 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -113,25 +113,18 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) if (self && [self commonInit]) { self.styleURL = nil; - self.accessToken = [MGLAccountManager accessToken]; return self; } return nil; } -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken -{ - return [self initWithFrame:frame accessToken:accessToken styleURL:nil]; -} - -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL +- (instancetype)initWithFrame:(CGRect)frame styleURL:(NSURL *)styleURL { self = [super initWithFrame:frame]; if (self && [self commonInit]) { - self.accessToken = accessToken; self.styleURL = styleURL; } @@ -153,19 +146,18 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) - (NSString *)accessToken { - NSString *accessToken = @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty; - return accessToken ? accessToken : [MGLAccountManager accessToken]; + NSAssert(NO, @"-[MGLMapView accessToken] has been removed. Use +[MGLAccountManager accessToken] or get MGLMapboxAccessToken from the Info.plist."); + return nil; } - (void)setAccessToken:(NSString *)accessToken { - _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); - [MGLAccountManager setAccessToken:accessToken.mgl_stringOrNilIfEmpty]; + NSAssert(NO, @"-[MGLMapView setAccessToken:] has been replaced by +[MGLAccountManager setAccessToken:].\n\nIf you previously set this access token in a storyboard inspectable, select the MGLMapView in Interface Builder and delete the “accessToken” entry from the User Defined Runtime Attributes section of the Identity inspector. Then go to the Info.plist file and set MGLMapboxAccessToken to “%@”.", accessToken); } + (NSSet *)keyPathsForValuesAffectingStyleURL { - return [NSSet setWithObjects:@"mapID", @"accessToken", nil]; + return [NSSet setWithObjects:@"mapID", nil]; } - (NSURL *)styleURL @@ -274,6 +266,10 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) } _mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor); + // mbgl::Map keeps its own copy of the access token. + NSString *accessToken = [MGLAccountManager accessToken]; + _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); + // Notify map object when network reachability status changes. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) @@ -1557,7 +1553,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) + (NSSet *)keyPathsForValuesAffectingMapID { - return [NSSet setWithObjects:@"styleURL", @"accessToken", nil]; + return [NSSet setWithObjects:@"styleURL", nil]; } - (NSString *)mapID @@ -2495,7 +2491,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) self.layer.borderColor = [UIColor colorWithWhite:184/255. alpha:1].CGColor; self.layer.borderWidth = 1; - if (self.accessToken) + if ([MGLAccountManager accessToken]) { self.layer.backgroundColor = [UIColor colorWithRed:59/255. green:178/255. @@ -2560,7 +2556,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) // More explanation UILabel *explanationLabel2 = [[UILabel alloc] init]; - explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector or in an MGLMapboxAccessToken entry in the Info.plist file."; + explanationLabel2.text = @"and set it as the value of MGLMapboxAccessToken in the Info.plist file."; explanationLabel2.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; explanationLabel2.numberOfLines = 0; explanationLabel2.translatesAutoresizingMaskIntoConstraints = NO; From a081f1af5b7c173da5f5c1beaec8c274aeb353de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 20 May 2015 10:47:42 -0700 Subject: [PATCH 23/72] Removed redundant declaration --- platform/ios/MGLAccountManager.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index d5b89e9f9..97d7e5e5e 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -9,8 +9,6 @@ @property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; @property (atomic) NSString *accessToken; -+ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut; - @end From 51618c35d79cfb237e62e70993182e87903c3ccd Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 20 May 2015 11:07:23 -0700 Subject: [PATCH 24/72] update README to mention desktop style toggling --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6b15f596c..bfd64f3b8 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,7 @@ Some styles in JSON format are included at `./styles`. See the [style spec](http ## Desktop +- Press `S` to cycle through bundled styles - Press `X` to reset the transform - Press `N` to reset north - Press `Tab` to toggle debug information From 90a50c0c4150080f725cc6b66909eef58a2a9b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 20 May 2015 11:49:59 -0700 Subject: [PATCH 25/72] Observe access token changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The singleton `MGLAccountManager` wants to be the sole arbiter of the access token, but each instance of `mbgl::Map` (`mbgl::DefaultFileSource` in #1607) has its own copy of the access token. Now `MGLMapView` observes for changes to the `MGLAccountManager`’s access token and synchronizes `mbgl::Map` with it. --- gyp/platform-ios.gypi | 1 + platform/ios/MGLAccountManager.m | 2 +- platform/ios/MGLAccountManager_Private.h | 10 ++++++++++ platform/ios/MGLMapView.mm | 22 ++++++++++++++++++---- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 platform/ios/MGLAccountManager_Private.h diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index 7e91648c4..12cbd9592 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -27,6 +27,7 @@ '../platform/ios/MGLFileCache.h', '../platform/ios/MGLFileCache.mm', '../include/mbgl/ios/MGLAccountManager.h', + '../platform/ios/MGLAccountManager_Private.h', '../platform/ios/MGLAccountManager.m', '../include/mbgl/ios/MGLAnnotation.h', '../include/mbgl/ios/MGLUserLocation.h', diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 97d7e5e5e..38ef1f4ca 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -1,6 +1,6 @@ #import -#import "MGLAccountManager.h" +#import "MGLAccountManager_Private.h" #import "MGLMapboxEvents_Private.h" #import "NSProcessInfo+MGLAdditions.h" diff --git a/platform/ios/MGLAccountManager_Private.h b/platform/ios/MGLAccountManager_Private.h new file mode 100644 index 000000000..3cc05b09f --- /dev/null +++ b/platform/ios/MGLAccountManager_Private.h @@ -0,0 +1,10 @@ +#import "MGLAccountManager.h" + +@interface MGLAccountManager (Private) + +/** Returns the shared instance of the `MGLAccountManager` class. */ ++ (instancetype)sharedManager; + +@property (atomic) NSString *accessToken; + +@end diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index cb89c58d4..997d5734a 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -20,7 +20,7 @@ #import "NSString+MGLAdditions.h" #import "NSProcessInfo+MGLAdditions.h" #import "NSException+MGLAdditions.h" -#import "MGLAccountManager.h" +#import "MGLAccountManager_Private.h" #import "MGLAnnotation.h" #import "MGLUserLocationAnnotationView.h" #import "MGLUserLocation_Private.h" @@ -266,9 +266,12 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) } _mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor); - // mbgl::Map keeps its own copy of the access token. - NSString *accessToken = [MGLAccountManager accessToken]; - _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); + // Observe for changes to the global access token (and find out the current one). + [[MGLAccountManager sharedManager] addObserver:self + forKeyPath:@"accessToken" + options:(NSKeyValueObservingOptionInitial | + NSKeyValueObservingOptionNew) + context:NULL]; // Notify map object when network reachability status changes. [[NSNotificationCenter defaultCenter] addObserver:self @@ -410,6 +413,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) [_regionChangeDelegateQueue cancelAllOperations]; [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; if (_mbglMap) { @@ -1292,6 +1296,16 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) #pragma mark - Properties - +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(__unused void *)context +{ + // Synchronize mbgl::Map’s access token with the global one in MGLAccountManager. + if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) + { + NSString *accessToken = change[NSKeyValueChangeNewKey]; + _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); + } +} + + (NSSet *)keyPathsForValuesAffectingZoomEnabled { return [NSSet setWithObject:@"allowsZooming"]; From 44caf2c7a97bc3b1314cc88dbf2c66ddaf5da2b0 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 May 2015 14:18:39 -0500 Subject: [PATCH 26/72] #1595 - Improving stability by moving MGLEventTypeAppUserTurnstile after the strongSelf check --- platform/ios/MGLMapboxEvents.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 364a05180..6b15df145 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -433,6 +433,10 @@ const NSTimeInterval MGLFlushInterval = 60; dispatch_async(_serialQueue, ^{ + MGLMapboxEvents *strongSelf = weakSelf; + + if ( ! strongSelf) return; + if ([MGLEventTypeAppUserTurnstile isEqualToString:event]) { // Build only IDFV event NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; @@ -442,15 +446,11 @@ const NSTimeInterval MGLFlushInterval = 60; [_eventQueue addObject:vevt]; // Flush - [MGLMapboxEvents flush]; + [self flush]; return; } - MGLMapboxEvents *strongSelf = weakSelf; - - if ( ! strongSelf) return; - // Metrics Collection Has Been Paused if (_paused) { return; From a29587726cb1cedd5dc95532b731c4d4b6d7932b Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 May 2015 14:32:16 -0500 Subject: [PATCH 27/72] #1595 - Moving MGLEventTypeAppUserTurnstile event to end of MGLMapboxEvents init method to ensure it only gets called once --- platform/ios/MGLAccountManager.m | 5 ++--- platform/ios/MGLMapboxEvents.m | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 1a9bbe47a..a49433777 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -51,9 +51,8 @@ [[MGLAccountManager sharedManager] setAccessToken:accessToken]; // Update MGLMapboxEvents - // NOTE: This is (likely) the initial setup of MGLMapboxEvents (via implicit call to +[MGLMapboxEvents sharedManager]) - // Turn the Mapbox Turnstile to Count App Users - [MGLMapboxEvents pushEvent:MGLEventTypeAppUserTurnstile withAttributes:nil]; + // NOTE: This is (likely) the initial setup of MGLMapboxEvents + [MGLMapboxEvents sharedManager]; } + (NSString *) accessToken { diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 6b15df145..b6daaab3b 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -278,6 +278,9 @@ const NSTimeInterval MGLFlushInterval = 60; MGLMapboxEvents *strongSelf = weakSelf; [strongSelf validate]; }]; + + // Turn the Mapbox Turnstile to Count App Users + [self pushEvent:MGLEventTypeAppUserTurnstile withAttributes:nil]; } return self; } From cbcc3a3e4912077f78e63ea4e470342f894e1630 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 May 2015 15:05:56 -0500 Subject: [PATCH 28/72] #1595 - Separating pushTurnstileEvent from primary pushEvent infrastructure. Adding event, created, and appBundleId to posted Turnstile Event data model. --- platform/ios/MGLMapboxEvents.m | 45 ++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index b6daaab3b..db5949a31 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -280,7 +280,9 @@ const NSTimeInterval MGLFlushInterval = 60; }]; // Turn the Mapbox Turnstile to Count App Users - [self pushEvent:MGLEventTypeAppUserTurnstile withAttributes:nil]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [self pushTurnstileEvent]; + }); } return self; } @@ -419,6 +421,31 @@ const NSTimeInterval MGLFlushInterval = 60; } } +- (void) pushTurnstileEvent { + + __weak MGLMapboxEvents *weakSelf = self; + + dispatch_async(_serialQueue, ^{ + + MGLMapboxEvents *strongSelf = weakSelf; + + if ( ! strongSelf) return; + + // Build only IDFV event + NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + NSDictionary *vevt = @{@"event" : MGLEventTypeAppUserTurnstile, + @"created" : [strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]], + @"appBundleId" : strongSelf.appBundleId, + @"vendorId": vid}; + + // Add to Queue + [_eventQueue addObject:vevt]; + + // Flush + [self flush]; + }); +} + // Can be called from any thread. Can be called rapidly from // the UI thread, so performance is paramount. // @@ -440,20 +467,6 @@ const NSTimeInterval MGLFlushInterval = 60; if ( ! strongSelf) return; - if ([MGLEventTypeAppUserTurnstile isEqualToString:event]) { - // Build only IDFV event - NSString *vid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; - NSDictionary *vevt = @{@"vendorId": vid}; - - // Add to Queue - [_eventQueue addObject:vevt]; - - // Flush - [self flush]; - - return; - } - // Metrics Collection Has Been Paused if (_paused) { return; @@ -502,7 +515,7 @@ const NSTimeInterval MGLFlushInterval = 60; [_eventQueue addObject:finalEvent]; // Has Flush Limit Been Reached? - if (_eventQueue.count >= MGLMaximumEventsPerFlush || [MGLEventTypeAppUserTurnstile isEqualToString:event]) { + if (_eventQueue.count >= MGLMaximumEventsPerFlush) { [strongSelf flush]; } else if (_eventQueue.count == 1) { // If this is first new event on queue start timer, From a47438d42adddad9838048cb4c5996a3eadb1c6b Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 20 May 2015 15:12:48 -0500 Subject: [PATCH 29/72] #1595 - Changing to strongSelf --- platform/ios/MGLMapboxEvents.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index db5949a31..011040097 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -442,7 +442,7 @@ const NSTimeInterval MGLFlushInterval = 60; [_eventQueue addObject:vevt]; // Flush - [self flush]; + [strongSelf flush]; }); } From 710ec54a5544eabd80df29e5854ee72cc737af80 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Thu, 21 May 2015 09:00:03 +1000 Subject: [PATCH 30/72] Update Android gradle plugin to 1.2.3 --- android/java/MapboxGLAndroidSDK/build.gradle | 2 +- android/java/MapboxGLAndroidSDKTestApp/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/java/MapboxGLAndroidSDK/build.gradle b/android/java/MapboxGLAndroidSDK/build.gradle index f0659b8c7..39e46fcc0 100644 --- a/android/java/MapboxGLAndroidSDK/build.gradle +++ b/android/java/MapboxGLAndroidSDK/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.android.tools.build:gradle:1.2.3' classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' } } diff --git a/android/java/MapboxGLAndroidSDKTestApp/build.gradle b/android/java/MapboxGLAndroidSDKTestApp/build.gradle index 5f2db91d7..46c95c21e 100644 --- a/android/java/MapboxGLAndroidSDKTestApp/build.gradle +++ b/android/java/MapboxGLAndroidSDKTestApp/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.android.tools.build:gradle:1.2.3' classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' } } From cea926c62e46619e71306a578be45eac59d3fc58 Mon Sep 17 00:00:00 2001 From: Leith Bade Date: Thu, 21 May 2015 09:49:07 +1000 Subject: [PATCH 31/72] Fix swapped lat/lng --- .../src/main/java/com/mapbox/mapboxgl/views/MapView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java index da4b40c4c..e482c0be5 100644 --- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java +++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/views/MapView.java @@ -149,9 +149,9 @@ public class MapView extends SurfaceView { // Load the attributes TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapView, 0, 0); try { - double centerLongitude = typedArray.getFloat(R.styleable.MapView_centerLongitude, 0.0f); double centerLatitude = typedArray.getFloat(R.styleable.MapView_centerLatitude, 0.0f); - LatLng centerCoordinate = new LatLng(centerLongitude, centerLatitude); + double centerLongitude = typedArray.getFloat(R.styleable.MapView_centerLongitude, 0.0f); + LatLng centerCoordinate = new LatLng(centerLatitude, centerLongitude); setCenterCoordinate(centerCoordinate); setZoomLevel(typedArray.getFloat(R.styleable.MapView_zoomLevel, 0.0f)); // need to set zoom level first because of limitation on rotating when zoomed out setDirection(typedArray.getFloat(R.styleable.MapView_direction, 0.0f)); From 911a8ffc603f4bf380b5f565dea5f0319a5d37b0 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 12 May 2015 10:01:19 -0700 Subject: [PATCH 32/72] Add action sheet shortcut to Settings.app metrics opt-out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only applicable to iOS 8+. Checks if metrics setting has been declared to be offered in app, if not: adds ℹ️ action to open the app's Settings.app section. Fixes #1519. Squash of #1529. --- platform/ios/MGLMapView.mm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 5d1410751..ca0b9bc78 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -294,6 +294,12 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) @"Improve This Map", nil]; + // iOS 8+: add action that opens app's Settings.app panel, if applicable + if (&UIApplicationOpenSettingsURLString != NULL && ! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp]) + { + [_attributionSheet addButtonWithTitle:@"Adjust Privacy Settings"]; + } + // setup compass // _compass = [[UIImageView alloc] initWithImage:[MGLMapView resourceImageNamed:@"Compass.png"]]; @@ -1270,6 +1276,11 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) [[UIApplication sharedApplication] openURL: [NSURL URLWithString:feedbackURL]]; } + // skips to 4 because button is conditionally added after cancel (index 3) + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 4) + { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + } } #pragma mark - Properties - From 70381d2705991b15a1861b3162f50aa56961343c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 21 May 2015 01:49:53 -0700 Subject: [PATCH 33/72] Fixed up various Info.plist edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need to look in the main bundle for Info.plist settings, because the developer has no access to the framework’s Info.plist. Need to check MGLMapboxMetricsEnabledSettingShownInApp before MGLMapboxAccessToken; otherwise, `MGLMapboxEvents` inspects the Settings bundle plist before MGLMapboxMetricsEnabledSettingShownInApp is even checked. --- platform/ios/MGLAccountManager.m | 8 +++++--- platform/ios/MGLMapboxEvents.m | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 2f246b7d9..03a90c31b 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -15,13 +15,15 @@ @implementation MGLAccountManager + (void)load { - // Read initial configuration from Info.plist. - NSBundle *bundle = [NSBundle bundleForClass:self]; - self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; + // Read the initial configuration from Info.plist. The shown-in-app setting + // preempts the Settings bundle check in -[MGLMapboxEvents init] triggered + // by setting the access token. + NSBundle *bundle = [NSBundle mainBundle]; NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; if (shownInAppNumber) { [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; } + self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; } // Can be called from any thread. diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index a0e771ad0..1079899ce 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -177,7 +177,7 @@ const NSTimeInterval MGLFlushInterval = 60; + (void)initialize { if (self == [MGLMapboxEvents class]) { - NSBundle *bundle = [NSBundle bundleForClass:self]; + NSBundle *bundle = [NSBundle mainBundle]; NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccountType"]; [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"MGLMapboxAccountType": accountTypeNumber ? accountTypeNumber : @0, @@ -198,7 +198,8 @@ const NSTimeInterval MGLFlushInterval = 60; self = [super init]; if (self) { - if (! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp]) { + if (! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp] && + [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { // Opt Out is not configured in UI, so check for Settings.bundle // Put Settings bundle into memory id defaultEnabledValue; From c718d2ea660f4fa3366caad347bb6577a679b968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 21 May 2015 01:51:18 -0700 Subject: [PATCH 34/72] Made accessToken uninspectable --- include/mbgl/ios/MGLMapView+IBAdditions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/mbgl/ios/MGLMapView+IBAdditions.h b/include/mbgl/ios/MGLMapView+IBAdditions.h index df9a19a6b..69998a474 100644 --- a/include/mbgl/ios/MGLMapView+IBAdditions.h +++ b/include/mbgl/ios/MGLMapView+IBAdditions.h @@ -8,7 +8,6 @@ // inspectables declared in MGLMapView.h are always sorted before those in // MGLMapView+IBAdditions.h, due to ASCII sort order. -@property (nonatomic) IBInspectable NSString *accessToken; @property (nonatomic) IBInspectable NSString *mapID; // Convenience properties related to the initial viewport. These properties From dfd6ff00a239ef7c4762346edf798aa5dfb7bf3f Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Thu, 21 May 2015 03:13:55 -0700 Subject: [PATCH 35/72] Update tests for access token changes --- test/ios/App-Info.plist | 4 ++++ test/ios/MGLTAppDelegate.m | 2 -- test/ios/MGLTViewController.m | 3 +-- test/ios/MetricsTests.m | 6 ------ 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/test/ios/App-Info.plist b/test/ios/App-Info.plist index d7e9d5c46..effff2063 100644 --- a/test/ios/App-Info.plist +++ b/test/ios/App-Info.plist @@ -2,6 +2,8 @@ + MGLMapboxAccessToken + pk.eyJ1IjoianVzdGluIiwiYSI6Ik9RX3RRQzAifQ.dmOg_BAp1ywuDZMM7YsXRg CFBundleDevelopmentRegion en CFBundleDisplayName @@ -34,6 +36,8 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + MGLMapboxMetricsEnabledSettingShownInApp + UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait diff --git a/test/ios/MGLTAppDelegate.m b/test/ios/MGLTAppDelegate.m index bbd67821f..3fa68b6da 100644 --- a/test/ios/MGLTAppDelegate.m +++ b/test/ios/MGLTAppDelegate.m @@ -13,8 +13,6 @@ wrapper.toolbarHidden = YES; [self.window makeKeyAndVisible]; - [MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:YES]; // a lie, but a convenient one - return YES; } diff --git a/test/ios/MGLTViewController.m b/test/ios/MGLTViewController.m index bdce2202d..e3357616f 100644 --- a/test/ios/MGLTViewController.m +++ b/test/ios/MGLTViewController.m @@ -10,8 +10,7 @@ { [super viewDidLoad]; - _mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds - accessToken:@"pk.eyJ1IjoianVzdGluIiwiYSI6Ik9RX3RRQzAifQ.dmOg_BAp1ywuDZMM7YsXRg"]; + _mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds]; _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [self.view addSubview:_mapView]; diff --git a/test/ios/MetricsTests.m b/test/ios/MetricsTests.m index 5b1a7956e..758cf1f5b 100644 --- a/test/ios/MetricsTests.m +++ b/test/ios/MetricsTests.m @@ -60,12 +60,6 @@ XCTAssertEqualObjects([[MGLMapboxEvents sharedManager] appBundleId], @"com.mapbox.Mapbox-GL-Tests"); } -- (void)testTokenSetViaMapView { - [tester.mapView setAccessToken:@"test_token"]; - - XCTAssertEqualObjects([[MGLMapboxEvents sharedManager] token], @"test_token"); -} - - (void)testResumeMetricsCollection { [MGLMapboxEvents resumeMetricsCollection]; From e74997e2c18a39355bde6caf9754a23c553b6853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 21 May 2015 08:53:40 -0700 Subject: [PATCH 36/72] Clarified IB designable message Access tokens are only required for showing Mapbox-hosted maps. --- platform/ios/MGLMapView.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 215be14b5..8df16ce38 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -2523,7 +2523,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) // Explanation UILabel *explanationLabel = [[UILabel alloc] init]; - explanationLabel.text = @"To display a map here, you must provide a Mapbox access token. Get an access token from:"; + explanationLabel.text = @"To display a Mapbox-hosted map here, you must provide an access token. Get an access token from:"; explanationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; explanationLabel.numberOfLines = 0; explanationLabel.translatesAutoresizingMaskIntoConstraints = NO; From 93f92b7805af1cf7ede158661431f06c67dc5950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 21 May 2015 10:10:35 -0700 Subject: [PATCH 37/72] Rewrote IB designable message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IB designables inside frameworks have no access whatsoever to the host app’s bundle (especially if the host app lacks any designables of its own). So it has no way of knowing whether the access token is set in Info.plist. We could continue to check whether it was set programmatically, but we’d still have no way of knowing whether the host app has a Settings bundle, the other prerequisite for displaying Mapbox maps. Therefore, this change removes the Mapbox logo from the designable and displays a reworded reminder unconditionally. It now displays the URL of the “First steps with Mapbox GL for iOS” guide. I kept Mapbox blue in the designable, but as a border, so you can easily tell where the view ends (a major usability problem for custom views in IB). --- platform/ios/MGLMapView.mm | 215 +++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 119 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 8df16ce38..10e85ee5a 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -36,7 +36,7 @@ class MBGLView; NSString *const MGLDefaultStyleName = @"mapbox-streets"; NSString *const MGLStyleVersion = @"7"; NSString *const MGLDefaultStyleMarkerSymbolName = @"default_marker"; -NSString *const MGLMapboxAccessTokenManagerURLDisplayString = @"mapbox.com/account/apps"; +NSString *const MGLMapboxSetupDocumentationURLDisplayString = @"mapbox.com/guides/first-steps-gl-ios"; const NSTimeInterval MGLAnimationDuration = 0.3; const CGSize MGLAnnotationUpdateViewportOutset = {150, 150}; @@ -2473,129 +2473,106 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) { [super prepareForInterfaceBuilder]; - self.layer.borderColor = [UIColor colorWithWhite:184/255. alpha:1].CGColor; - self.layer.borderWidth = 1; + self.layer.borderColor = [UIColor colorWithRed:59/255. + green:178/255. + blue:208/255. + alpha:0.8].CGColor; + self.layer.borderWidth = 4; + self.layer.backgroundColor = [UIColor whiteColor].CGColor; - if ([MGLAccountManager accessToken]) - { - self.layer.backgroundColor = [UIColor colorWithRed:59/255. - green:178/255. - blue:208/255. - alpha:0.8].CGColor; + UIView *diagnosticView = [[UIView alloc] init]; + diagnosticView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:diagnosticView]; - UIImage *image = [[self class] resourceImageNamed:@"mapbox.png"]; - UIImageView *previewView = [[UIImageView alloc] initWithImage:image]; - previewView.translatesAutoresizingMaskIntoConstraints = NO; - [self addSubview:previewView]; - [self addConstraint: - [NSLayoutConstraint constraintWithItem:previewView - attribute:NSLayoutAttributeCenterXWithinMargins - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterXWithinMargins - multiplier:1 - constant:0]]; - [self addConstraint: - [NSLayoutConstraint constraintWithItem:previewView - attribute:NSLayoutAttributeCenterYWithinMargins - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterYWithinMargins - multiplier:1 - constant:0]]; - } - else - { - UIView *diagnosticView = [[UIView alloc] init]; - diagnosticView.translatesAutoresizingMaskIntoConstraints = NO; - [self addSubview:diagnosticView]; + // Headline + UILabel *headlineLabel = [[UILabel alloc] init]; + headlineLabel.text = @"MGLMapView"; + headlineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + headlineLabel.textAlignment = NSTextAlignmentCenter; + headlineLabel.numberOfLines = 1; + headlineLabel.translatesAutoresizingMaskIntoConstraints = NO; + [headlineLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [diagnosticView addSubview:headlineLabel]; - // Headline - UILabel *headlineLabel = [[UILabel alloc] init]; - headlineLabel.text = @"No Access Token"; - headlineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; - headlineLabel.textAlignment = NSTextAlignmentCenter; - headlineLabel.numberOfLines = 1; - headlineLabel.translatesAutoresizingMaskIntoConstraints = NO; - [headlineLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow - forAxis:UILayoutConstraintAxisHorizontal]; - [diagnosticView addSubview:headlineLabel]; + // Explanation + UILabel *explanationLabel = [[UILabel alloc] init]; + explanationLabel.text = (@"To display a Mapbox-hosted map here:\n\n" + @"1. Set MGLMapboxAccessToken to your access token in Info.plist\n" + @"2. Add a Settings bundle that allows the user to turn Mapbox Metrics on and off\n\n" + @"For detailed instructions, see:"); + explanationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + explanationLabel.numberOfLines = 0; + explanationLabel.translatesAutoresizingMaskIntoConstraints = NO; + [explanationLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [diagnosticView addSubview:explanationLabel]; - // Explanation - UILabel *explanationLabel = [[UILabel alloc] init]; - explanationLabel.text = @"To display a Mapbox-hosted map here, you must provide an access token. Get an access token from:"; - explanationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; - explanationLabel.numberOfLines = 0; - explanationLabel.translatesAutoresizingMaskIntoConstraints = NO; - [explanationLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow - forAxis:UILayoutConstraintAxisHorizontal]; - [diagnosticView addSubview:explanationLabel]; + // Link + UIButton *linkButton = [UIButton buttonWithType:UIButtonTypeSystem]; + [linkButton setTitle:MGLMapboxSetupDocumentationURLDisplayString forState:UIControlStateNormal]; + linkButton.translatesAutoresizingMaskIntoConstraints = NO; + linkButton.titleLabel.numberOfLines = 0; + [linkButton setContentCompressionResistancePriority:UILayoutPriorityDefaultLow + forAxis:UILayoutConstraintAxisHorizontal]; + [diagnosticView addSubview:linkButton]; - // Link - UIButton *linkButton = [UIButton buttonWithType:UIButtonTypeSystem]; - [linkButton setTitle:MGLMapboxAccessTokenManagerURLDisplayString forState:UIControlStateNormal]; - linkButton.translatesAutoresizingMaskIntoConstraints = NO; - [linkButton setContentCompressionResistancePriority:UILayoutPriorityDefaultLow - forAxis:UILayoutConstraintAxisHorizontal]; - [diagnosticView addSubview:linkButton]; - - // More explanation - UILabel *explanationLabel2 = [[UILabel alloc] init]; - explanationLabel2.text = @"and set it as the value of MGLMapboxAccessToken in the Info.plist file."; - explanationLabel2.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; - explanationLabel2.numberOfLines = 0; - explanationLabel2.translatesAutoresizingMaskIntoConstraints = NO; - [explanationLabel2 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow - forAxis:UILayoutConstraintAxisHorizontal]; - [diagnosticView addSubview:explanationLabel2]; - - // Constraints - NSDictionary *views = @{ - @"container": diagnosticView, - @"headline": headlineLabel, - @"explanation": explanationLabel, - @"link": linkButton, - @"explanation2": explanationLabel2, - }; - [self addConstraint: - [NSLayoutConstraint constraintWithItem:diagnosticView - attribute:NSLayoutAttributeCenterYWithinMargins - relatedBy:NSLayoutRelationEqual - toItem:self - attribute:NSLayoutAttributeCenterYWithinMargins - multiplier:1 - constant:0]]; - [self addConstraints: - [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[container(20@20)]-|" - options:NSLayoutFormatAlignAllCenterY - metrics:nil - views:views]]; - [self addConstraints: - [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[headline]-[explanation]-[link]-[explanation2]|" - options:0 - metrics:nil - views:views]]; - [self addConstraints: - [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[headline]|" - options:0 - metrics:nil - views:views]]; - [self addConstraints: - [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[explanation]|" - options:0 - metrics:nil - views:views]]; - [self addConstraints: - [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[link]|" - options:0 - metrics:nil - views:views]]; - [self addConstraints: - [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[explanation2]|" - options:0 - metrics:nil - views:views]]; - } + // Constraints + NSDictionary *views = @{ + @"container": diagnosticView, + @"headline": headlineLabel, + @"explanation": explanationLabel, + @"link": linkButton, + }; + [self addConstraint: + [NSLayoutConstraint constraintWithItem:diagnosticView + attribute:NSLayoutAttributeCenterYWithinMargins + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterYWithinMargins + multiplier:1 + constant:0]]; + [self addConstraint: + [NSLayoutConstraint constraintWithItem:diagnosticView + attribute:NSLayoutAttributeTopMargin + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTopMargin + multiplier:1 + constant:8]]; + [self addConstraint: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottomMargin + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:diagnosticView + attribute:NSLayoutAttributeBottomMargin + multiplier:1 + constant:8]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[container(20@20)]-|" + options:NSLayoutFormatAlignAllCenterY + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[headline]-[explanation]-[link]|" + options:0 + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[headline]|" + options:0 + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[explanation]|" + options:0 + metrics:nil + views:views]]; + [self addConstraints: + [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[link]|" + options:0 + metrics:nil + views:views]]; } class MBGLView : public mbgl::View From 2200c51a337d8f10bf61037d282645add5622608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 21 May 2015 13:29:46 -0700 Subject: [PATCH 38/72] Removed unavailable method implementation This class method is marked unavailable in MGLAccountManager.h, so this code can never be reached. --- platform/ios/MGLAccountManager.m | 4 ---- 1 file changed, 4 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 03a90c31b..71987786c 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -50,10 +50,6 @@ return _sharedManager; } -+ (void) setMapboxMetricsEnabledSettingShownInApp:(BOOL)shown { - [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = shown; -} - + (BOOL) mapboxMetricsEnabledSettingShownInApp { return [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp; } From ddc8d637305c1d3c9301f2b8a972dd48ddb3580b Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Thu, 21 May 2015 14:30:54 -0700 Subject: [PATCH 39/72] Add iOS tests support for iPhone 6/6+ screen sizes --- test/ios/App-Info.plist | 10 +++-- test/ios/LaunchScreen.xib | 45 ++++++++++++++++++++ test/ios/ios-tests.xcodeproj/project.pbxproj | 4 ++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 test/ios/LaunchScreen.xib diff --git a/test/ios/App-Info.plist b/test/ios/App-Info.plist index effff2063..f5a44890e 100644 --- a/test/ios/App-Info.plist +++ b/test/ios/App-Info.plist @@ -2,8 +2,6 @@ - MGLMapboxAccessToken - pk.eyJ1IjoianVzdGluIiwiYSI6Ik9RX3RRQzAifQ.dmOg_BAp1ywuDZMM7YsXRg CFBundleDevelopmentRegion en CFBundleDisplayName @@ -26,6 +24,12 @@ 1.0 LSRequiresIPhoneOS + MGLMapboxAccessToken + pk.eyJ1IjoianVzdGluIiwiYSI6Ik9RX3RRQzAifQ.dmOg_BAp1ywuDZMM7YsXRg + MGLMapboxMetricsEnabledSettingShownInApp + + UILaunchStoryboardName + LaunchScreen UIRequiredDeviceCapabilities armv7 @@ -36,8 +40,6 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - MGLMapboxMetricsEnabledSettingShownInApp - UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait diff --git a/test/ios/LaunchScreen.xib b/test/ios/LaunchScreen.xib new file mode 100644 index 000000000..f14a79070 --- /dev/null +++ b/test/ios/LaunchScreen.xib @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/ios/ios-tests.xcodeproj/project.pbxproj b/test/ios/ios-tests.xcodeproj/project.pbxproj index 4f31a5b4a..9e36d0858 100644 --- a/test/ios/ios-tests.xcodeproj/project.pbxproj +++ b/test/ios/ios-tests.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 96567A231B0E84CD00D78776 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96567A221B0E84CD00D78776 /* LaunchScreen.xib */; }; DD043363196DBBD500E6F39D /* MGLTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */; }; DD043364196DBBD500E6F39D /* MGLTViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD043360196DBBD500E6F39D /* MGLTViewController.m */; }; DD043366196DBBE000E6F39D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DD043365196DBBE000E6F39D /* main.m */; }; @@ -81,6 +82,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 96567A221B0E84CD00D78776 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = SOURCE_ROOT; }; DACAD7111B08719F009119DC /* MGLMapboxEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLMapboxEvents.h; path = ../../platform/ios/MGLMapboxEvents.h; sourceTree = SOURCE_ROOT; }; DD043323196DB9BC00E6F39D /* Mapbox GL Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL Tests.app"; sourceTree = BUILT_PRODUCTS_DIR; }; DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLTAppDelegate.m; sourceTree = SOURCE_ROOT; }; @@ -219,6 +221,7 @@ children = ( DD043367196DBCC200E6F39D /* App-Info.plist */, DD043365196DBBE000E6F39D /* main.m */, + 96567A221B0E84CD00D78776 /* LaunchScreen.xib */, ); name = "Supporting Files"; sourceTree = ""; @@ -445,6 +448,7 @@ files = ( DD0581041ACB661200B112C9 /* Headers in Resources */, DD0581061ACB661C00B112C9 /* MapboxGL.bundle in Resources */, + 96567A231B0E84CD00D78776 /* LaunchScreen.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 9c309808bda7374690445da73f815ddfe24b5d30 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Thu, 21 May 2015 14:59:43 -0700 Subject: [PATCH 40/72] Add iOS test project launch images for older devices, too --- .../AppIcon.appiconset/Contents.json | 162 ++++++++++++++++++ .../LaunchImage.launchimage/Contents.json | 53 ++++++ .../Default-568h@2x.png | Bin 0 -> 184 bytes .../LaunchImage.launchimage/Default@2x.png | Bin 0 -> 170 bytes test/ios/ios-tests.xcodeproj/project.pbxproj | 4 + 5 files changed, 219 insertions(+) create mode 100644 test/ios/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 test/ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png create mode 100644 test/ios/Images.xcassets/LaunchImage.launchimage/Default@2x.png diff --git a/test/ios/Images.xcassets/AppIcon.appiconset/Contents.json b/test/ios/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..5008911f9 --- /dev/null +++ b/test/ios/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,162 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "57x57", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "50x50", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "72x72", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "car", + "size" : "120x120", + "scale" : "1x" + }, + { + "size" : "24x24", + "idiom" : "watch", + "scale" : "2x", + "role" : "notificationCenter", + "subtype" : "38mm" + }, + { + "size" : "27.5x27.5", + "idiom" : "watch", + "scale" : "2x", + "role" : "notificationCenter", + "subtype" : "42mm" + }, + { + "size" : "29x29", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "watch", + "role" : "companionSettings", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "watch", + "scale" : "2x", + "role" : "appLauncher", + "subtype" : "38mm" + }, + { + "size" : "44x44", + "idiom" : "watch", + "scale" : "2x", + "role" : "longLook", + "subtype" : "42mm" + }, + { + "size" : "86x86", + "idiom" : "watch", + "scale" : "2x", + "role" : "quickLook", + "subtype" : "38mm" + }, + { + "size" : "98x98", + "idiom" : "watch", + "scale" : "2x", + "role" : "quickLook", + "subtype" : "42mm" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json b/test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 000000000..628027f24 --- /dev/null +++ b/test/ios/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "filename" : "Default@2x.png", + "scale" : "2x" + }, + { + "extent" : "full-screen", + "idiom" : "iphone", + "subtype" : "retina4", + "filename" : "Default-568h@2x.png", + "minimum-system-version" : "7.0", + "orientation" : "portrait", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/test/ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/test/ios/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..208eea205a69e500b0bc99496dca3e8af7f4f79f GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sU@2f^28uX1mOBF}<^Z1%SL;m|?x$$F0=WgA vE{-7;ac>VXasqjW7ku~sE5m#gBtsh@lU~ojcxun%LXh#Eu6{1-oD!M2BK6SV_KF$egBxLR+za6d)U706BU yba4!+hc?L#?r#Eas270>sxvX Date: Thu, 21 May 2015 15:10:54 -0700 Subject: [PATCH 41/72] =?UTF-8?q?Change=20LaunchScreen=20text=20to=20?= =?UTF-8?q?=C2=A9=20because=20unicode=20is=20awesome?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/ios/LaunchScreen.xib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ios/LaunchScreen.xib b/test/ios/LaunchScreen.xib index f14a79070..e0c780d8d 100644 --- a/test/ios/LaunchScreen.xib +++ b/test/ios/LaunchScreen.xib @@ -12,7 +12,7 @@ -