summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorAnsis Brammanis <brammanis@gmail.com>2015-05-28 20:01:15 -0400
committerAnsis Brammanis <brammanis@gmail.com>2015-05-28 20:01:15 -0400
commitff6a5ce5bc674e17a24c3f18b305d5dd2f0e21b0 (patch)
tree405ec719109186590311262045ff1651b06e9506 /platform
parentfd19eb79056b8e62f037c0ae4532f4f7cc970580 (diff)
parent6c166b564ebb3acefb56bb4d39be4813851db4a7 (diff)
downloadqtlocation-mapboxgl-ff6a5ce5bc674e17a24c3f18b305d5dd2f0e21b0.tar.gz
Merge remote-tracking branch 'origin/master' into new-labelling
Conflicts: src/mbgl/map/source.cpp src/mbgl/map/source.hpp src/mbgl/map/tile_data.cpp src/mbgl/map/tile_parser.cpp src/mbgl/map/vector_tile_data.cpp src/mbgl/renderer/painter.cpp src/mbgl/renderer/symbol_bucket.cpp src/mbgl/text/glyph.hpp src/mbgl/text/glyph_store.cpp src/mbgl/text/placement.cpp test/suite
Diffstat (limited to 'platform')
-rw-r--r--platform/darwin/http_request_nsurl.mm28
-rw-r--r--platform/darwin/image.mm3
-rw-r--r--platform/darwin/reachability.m234
-rw-r--r--platform/default/asset_request_fs.cpp9
-rw-r--r--platform/default/asset_request_zip.cpp7
-rw-r--r--platform/default/headless_view.cpp7
-rw-r--r--platform/default/http_request_curl.cpp10
-rw-r--r--platform/default/image.cpp3
-rw-r--r--platform/default/image_reader.cpp4
-rw-r--r--platform/default/sqlite_cache.cpp16
-rw-r--r--platform/ios/MGLAccountManager.m23
-rw-r--r--platform/ios/MGLAccountManager_Private.h10
-rw-r--r--platform/ios/MGLMapView.mm406
-rw-r--r--platform/ios/MGLMapboxEvents.h1
-rw-r--r--platform/ios/MGLMapboxEvents.m60
15 files changed, 403 insertions, 418 deletions
diff --git a/platform/darwin/http_request_nsurl.mm b/platform/darwin/http_request_nsurl.mm
index 5ab4e1b43e..207c33b23c 100644
--- a/platform/darwin/http_request_nsurl.mm
+++ b/platform/darwin/http_request_nsurl.mm
@@ -2,7 +2,6 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/time.hpp>
#include <mbgl/util/parsedate.h>
@@ -91,6 +90,7 @@ public:
NSURLSession *session = nil;
NSString *userAgent = nil;
+ NSInteger accountType = 0;
};
HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
@@ -107,6 +107,8 @@ HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
// Write user agent string
userAgent = @"MapboxGL";
+
+ accountType = [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"];
}
}
@@ -153,17 +155,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:@"&"];
- }
- [url appendString:@"events=true"];
+ NSURL *url = [NSURL URLWithString:@(resource.url.c_str())];
+ 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:[NSURL URLWithString:url]];
+ NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
if (existingResponse) {
if (!existingResponse->etag.empty()) {
[req addValue:@(existingResponse->etag.c_str()) forHTTPHeaderField:@"If-None-Match"];
@@ -249,7 +249,7 @@ void HTTPRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error)
} else {
// TODO: Use different codes for host not found, timeout, invalid URL etc.
// These can be categorized in temporary and permanent errors.
- response = util::make_unique<Response>();
+ response = std::make_unique<Response>();
response->status = Response::Error;
response->message = [[error localizedDescription] UTF8String];
@@ -281,7 +281,7 @@ void HTTPRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error)
} else if ([res isKindOfClass:[NSHTTPURLResponse class]]) {
const long responseCode = [(NSHTTPURLResponse *)res statusCode];
- response = util::make_unique<Response>();
+ response = std::make_unique<Response>();
response->data = {(const char *)[data bytes], [data length]};
NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields];
@@ -337,7 +337,7 @@ void HTTPRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error)
} else {
// This should never happen.
status = ResponseStatus::PermanentError;
- response = util::make_unique<Response>();
+ response = std::make_unique<Response>();
response->status = Response::Error;
response->message = "response class is not NSHTTPURLResponse";
}
@@ -363,7 +363,7 @@ void HTTPRequest::retry() {
}
std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
- return util::make_unique<HTTPNSURLContext>(loop);
+ return std::make_unique<HTTPNSURLContext>(loop);
}
}
diff --git a/platform/darwin/image.mm b/platform/darwin/image.mm
index a9044774dc..f6a8a6783c 100644
--- a/platform/darwin/image.mm
+++ b/platform/darwin/image.mm
@@ -1,5 +1,4 @@
#include <mbgl/util/image.hpp>
-#include <mbgl/util/std.hpp>
#import <ImageIO/ImageIO.h>
@@ -98,7 +97,7 @@ Image::Image(const std::string &source_data) {
height = uint32_t(CGImageGetHeight(image));
CGRect rect = {{ 0, 0 }, { static_cast<CGFloat>(width), static_cast<CGFloat>(height) }};
- img = util::make_unique<char[]>(width * height * 4);
+ img = std::make_unique<char[]>(width * height * 4);
CGContextRef context = CGBitmapContextCreate(img.get(), width, height, 8, width * 4,
color_space, kCGImageAlphaPremultipliedLast);
if (!context) {
diff --git a/platform/darwin/reachability.m b/platform/darwin/reachability.m
index 8234659402..d1413321b7 100644
--- a/platform/darwin/reachability.m
+++ b/platform/darwin/reachability.m
@@ -27,32 +27,33 @@
#import <mbgl/platform/darwin/reachability.h>
+#import <sys/socket.h>
+#import <netinet/in.h>
+#import <netinet6/in6.h>
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import <netdb.h>
-NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification";
-@interface Reachability ()
+NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification";
-@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef;
+@interface MGLReachability ()
-#if NEEDS_DISPATCH_RETAIN_RELEASE
-@property (nonatomic, assign) dispatch_queue_t reachabilitySerialQueue;
-#else
+@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef;
@property (nonatomic, strong) dispatch_queue_t reachabilitySerialQueue;
-#endif
-
-
-@property (nonatomic, strong) id reachabilityObject;
+@property (nonatomic, strong) id reachabilityObject;
-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags;
-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags;
@end
+
static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags)
{
return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c",
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
#else
'X',
@@ -71,11 +72,8 @@ static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags)
static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target)
-#if __has_feature(objc_arc)
- Reachability *reachability = ((__bridge Reachability*)info);
-#else
- Reachability *reachability = ((Reachability*)info);
-#endif
+
+ MGLReachability *reachability = ((__bridge MGLReachability*)info);
// We probably don't need an autoreleasepool here, as GCD docs state each queue has its own autorelease pool,
// but what the heck eh?
@@ -86,61 +84,42 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
}
-@implementation Reachability
-
-@synthesize reachabilityRef;
-@synthesize reachabilitySerialQueue;
-
-@synthesize reachableOnWWAN;
-
-@synthesize reachableBlock;
-@synthesize unreachableBlock;
-
-@synthesize reachabilityObject;
+@implementation MGLReachability
#pragma mark - Class Constructor Methods
-+(Reachability*)reachabilityWithHostName:(NSString*)hostname
++(instancetype)reachabilityWithHostName:(NSString*)hostname
{
- return [Reachability reachabilityWithHostname:hostname];
+ return [MGLReachability reachabilityWithHostname:hostname];
}
-+(Reachability*)reachabilityWithHostname:(NSString*)hostname
++(instancetype)reachabilityWithHostname:(NSString*)hostname
{
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
if (ref)
{
id reachability = [[self alloc] initWithReachabilityRef:ref];
-#if __has_feature(objc_arc)
return reachability;
-#else
- return [reachability autorelease];
-#endif
-
}
return nil;
}
-+(Reachability *)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
++(instancetype)reachabilityWithAddress:(void *)hostAddress
{
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
if (ref)
{
id reachability = [[self alloc] initWithReachabilityRef:ref];
-#if __has_feature(objc_arc)
return reachability;
-#else
- return [reachability autorelease];
-#endif
}
return nil;
}
-+(Reachability *)reachabilityForInternetConnection
++(instancetype)reachabilityForInternetConnection
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
@@ -150,7 +129,7 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
return [self reachabilityWithAddress:&zeroAddress];
}
-+(Reachability*)reachabilityForLocalWiFi
++(instancetype)reachabilityForLocalWiFi
{
struct sockaddr_in localWifiAddress;
bzero(&localWifiAddress, sizeof(localWifiAddress));
@@ -165,13 +144,18 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
// Initialization methods
--(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref
+-(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref
{
self = [super init];
if (self != nil)
{
self.reachableOnWWAN = YES;
self.reachabilityRef = ref;
+
+ // We need to create a serial queue.
+ // We allocate this once for the lifetime of the notifier.
+
+ self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL);
}
return self;
@@ -187,14 +171,9 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
self.reachabilityRef = nil;
}
- self.reachableBlock = nil;
- self.unreachableBlock = nil;
-
-#if !(__has_feature(objc_arc))
- [super dealloc];
-#endif
-
-
+ self.reachableBlock = nil;
+ self.unreachableBlock = nil;
+ self.reachabilitySerialQueue = nil;
}
#pragma mark - Notifier Methods
@@ -206,75 +185,46 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
-(BOOL)startNotifier
{
- SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
-
- // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves
- // woah
- self.reachabilityObject = self;
-
-
-
- // First, we need to create a serial queue.
- // We allocate this once for the lifetime of the notifier.
- self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL);
- if(self.reachabilitySerialQueue == nil)
+ // allow start notifier to be called multiple times
+ if(self.reachabilityObject && (self.reachabilityObject == self))
{
- return NO;
+ return YES;
}
-#if __has_feature(objc_arc)
+
+ SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
context.info = (__bridge void *)self;
-#else
- context.info = (void *)self;
-#endif
- if (!SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context))
+ if(SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context))
{
+ // Set it as our reachability queue, which will retain the queue
+ if(SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue))
+ {
+ // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves
+ // woah
+ self.reachabilityObject = self;
+ return YES;
+ }
+ else
+ {
#ifdef DEBUG
- NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError()));
+ NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError()));
#endif
- // Clear out the dispatch queue
- if(self.reachabilitySerialQueue)
- {
-#if NEEDS_DISPATCH_RETAIN_RELEASE
- dispatch_release(self.reachabilitySerialQueue);
-#endif
- self.reachabilitySerialQueue = nil;
+ // UH OH - FAILURE - stop any callbacks!
+ SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);
}
-
- self.reachabilityObject = nil;
-
- return NO;
}
-
- // Set it as our reachability queue, which will retain the queue
- if(!SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue))
+ else
{
#ifdef DEBUG
- NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError()));
-#endif
-
- // UH OH - FAILURE!
-
- // First stop, any callbacks!
- SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);
-
- // Then clear out the dispatch queue.
- if(self.reachabilitySerialQueue)
- {
-#if NEEDS_DISPATCH_RETAIN_RELEASE
- dispatch_release(self.reachabilitySerialQueue);
+ NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError()));
#endif
- self.reachabilitySerialQueue = nil;
- }
-
- self.reachabilityObject = nil;
-
- return NO;
}
- return YES;
+ // if we get here we fail at the internet
+ self.reachabilityObject = nil;
+ return NO;
}
-(void)stopNotifier
@@ -285,14 +235,6 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
// Unregister target from the GCD serial dispatch queue.
SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL);
- if(self.reachabilitySerialQueue)
- {
-#if NEEDS_DISPATCH_RETAIN_RELEASE
- dispatch_release(self.reachabilitySerialQueue);
-#endif
- self.reachabilitySerialQueue = nil;
- }
-
self.reachabilityObject = nil;
}
@@ -318,7 +260,7 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
if( (flags & testcase) == testcase )
connectionUP = NO;
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE
if(flags & kSCNetworkReachabilityFlagsIsWWAN)
{
// We're on 3G.
@@ -345,11 +287,11 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
-(BOOL)isReachableViaWWAN
{
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE
SCNetworkReachabilityFlags flags = 0;
- if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
+ if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
{
// Check we're REACHABLE
if(flags & kSCNetworkReachabilityFlagsReachable)
@@ -370,12 +312,12 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
{
SCNetworkReachabilityFlags flags = 0;
- if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
+ if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
{
// Check we're reachable
if((flags & kSCNetworkReachabilityFlagsReachable))
{
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE
// Check we're NOT on WWAN
if((flags & kSCNetworkReachabilityFlagsIsWWAN))
{
@@ -401,10 +343,10 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
{
SCNetworkReachabilityFlags flags;
- if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
+ if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
{
- return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
- }
+ return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
+ }
return NO;
}
@@ -412,15 +354,15 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
// Dynamic, on demand connection?
-(BOOL)isConnectionOnDemand
{
- SCNetworkReachabilityFlags flags;
+ SCNetworkReachabilityFlags flags;
- if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
+ if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
{
- return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
- (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand)));
- }
+ return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
+ (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand)));
+ }
- return NO;
+ return NO;
}
// Is user intervention required?
@@ -428,13 +370,13 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
{
SCNetworkReachabilityFlags flags;
- if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
+ if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
{
- return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
- (flags & kSCNetworkReachabilityFlagsInterventionRequired));
- }
+ return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
+ (flags & kSCNetworkReachabilityFlagsInterventionRequired));
+ }
- return NO;
+ return NO;
}
@@ -447,7 +389,7 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
if([self isReachableViaWiFi])
return ReachableViaWiFi;
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE
return ReachableViaWWAN;
#endif
}
@@ -459,7 +401,7 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
{
SCNetworkReachabilityFlags flags = 0;
- if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
+ if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
{
return flags;
}
@@ -469,19 +411,19 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
-(NSString*)currentReachabilityString
{
- NetworkStatus temp = [self currentReachabilityStatus];
+ NetworkStatus temp = [self currentReachabilityStatus];
- if(temp == reachableOnWWAN)
- {
+ if(temp == ReachableViaWWAN)
+ {
// Updated for the fact that we have CDMA phones now!
- return NSLocalizedString(@"Cellular", @"");
- }
- if (temp == ReachableViaWiFi)
- {
- return NSLocalizedString(@"WiFi", @"");
- }
-
- return NSLocalizedString(@"No Connection", @"");
+ return NSLocalizedString(@"Cellular", @"");
+ }
+ if (temp == ReachableViaWiFi)
+ {
+ return NSLocalizedString(@"WiFi", @"");
+ }
+
+ return NSLocalizedString(@"No Connection", @"");
}
-(NSString*)currentReachabilityFlags
@@ -519,8 +461,8 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
- (NSString *) description
{
- NSString *description = [NSString stringWithFormat:@"<%@: %#x>",
- NSStringFromClass([self class]), (unsigned int) self];
+ NSString *description = [NSString stringWithFormat:@"<%@: %#x (%@)>",
+ NSStringFromClass([self class]), (unsigned int) self, [self currentReachabilityFlags]];
return description;
}
diff --git a/platform/default/asset_request_fs.cpp b/platform/default/asset_request_fs.cpp
index 9dae2e8a9c..04f85fbc3d 100644
--- a/platform/default/asset_request_fs.cpp
+++ b/platform/default/asset_request_fs.cpp
@@ -1,7 +1,6 @@
#include <mbgl/storage/asset_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/url.hpp>
#include <mbgl/util/uv.hpp>
@@ -114,7 +113,7 @@ void AssetRequest::fileStated(uv_fs_t *req) {
if (stat->st_size > std::numeric_limits<int>::max()) {
// File is too large for us to open this way because uv_buf's only support unsigned
// ints as maximum size.
- auto response = util::make_unique<Response>();
+ auto response = std::make_unique<Response>();
response->status = Response::Error;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
response->message = uv_strerror(uv_err_t {UV_EFBIG, 0});
@@ -126,7 +125,7 @@ void AssetRequest::fileStated(uv_fs_t *req) {
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
} else {
- self->response = util::make_unique<Response>();
+ self->response = std::make_unique<Response>();
#ifdef __APPLE__
self->response->modified = stat->st_mtimespec.tv_sec;
#else
@@ -184,7 +183,7 @@ void AssetRequest::notifyError(uv_fs_t *req) {
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0 && !self->canceled && req->result != UV_ECANCELED) {
- auto response = util::make_unique<Response>();
+ auto response = std::make_unique<Response>();
response->status = Response::Error;
response->message = uv::getFileRequestError(req);
self->notify(std::move(response), FileCache::Hint::No);
@@ -208,7 +207,7 @@ void AssetRequest::cancel() {
}
std::unique_ptr<AssetContext> AssetContext::createContext(uv_loop_t*) {
- return util::make_unique<AssetFSContext>();
+ return std::make_unique<AssetFSContext>();
}
}
diff --git a/platform/default/asset_request_zip.cpp b/platform/default/asset_request_zip.cpp
index 7666000d00..7fd93c55d1 100644
--- a/platform/default/asset_request_zip.cpp
+++ b/platform/default/asset_request_zip.cpp
@@ -3,7 +3,6 @@
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/log.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/uv.hpp>
@@ -178,7 +177,7 @@ void AssetRequest::fileStated(uv_zip_t *zip) {
notifyError("Could not determine file size in zip file");
cleanup(zip);
} else {
- response = util::make_unique<Response>();
+ response = std::make_unique<Response>();
// Allocate the space for reading the data.
response->data.resize(zip->stat->size);
@@ -247,7 +246,7 @@ void AssetRequest::notifyError(const char *message) {
MBGL_VERIFY_THREAD(tid);
if (!cancelled) {
- response = util::make_unique<Response>();
+ response = std::make_unique<Response>();
response->status = Response::Error;
response->message = message;
notify(std::move(response), FileCache::Hint::No);
@@ -261,7 +260,7 @@ void AssetRequest::cancel() {
}
std::unique_ptr<AssetContext> AssetContext::createContext(uv_loop_t* loop) {
- return util::make_unique<AssetZipContext>(loop);
+ return std::make_unique<AssetZipContext>(loop);
}
}
diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp
index aa07706d84..0f00c7563d 100644
--- a/platform/default/headless_view.cpp
+++ b/platform/default/headless_view.cpp
@@ -5,7 +5,6 @@
#include <mbgl/map/still_image.hpp>
-#include <mbgl/util/std.hpp>
#include <stdexcept>
#include <sstream>
@@ -172,15 +171,15 @@ std::unique_ptr<StillImage> HeadlessView::readStillImage() {
const unsigned int w = dimensions.pixelWidth();
const unsigned int h = dimensions.pixelHeight();
- auto image = util::make_unique<StillImage>();
+ auto image = std::make_unique<StillImage>();
image->width = w;
image->height = h;
- image->pixels = util::make_unique<uint32_t[]>(w * h);
+ image->pixels = std::make_unique<uint32_t[]>(w * h);
MBGL_CHECK_ERROR(glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels.get()));
const int stride = w * 4;
- auto tmp = util::make_unique<char[]>(stride);
+ auto tmp = std::make_unique<char[]>(stride);
char *rgba = reinterpret_cast<char *>(image->pixels.get());
for (int i = 0, j = h - 1; i < j; i++, j--) {
std::memcpy(tmp.get(), rgba + i * stride, stride);
diff --git a/platform/default/http_request_curl.cpp b/platform/default/http_request_curl.cpp
index 45115b621f..8599ea05ee 100644
--- a/platform/default/http_request_curl.cpp
+++ b/platform/default/http_request_curl.cpp
@@ -385,7 +385,7 @@ static CURLcode sslctx_function(CURL * /* curl */, void *sslctx, void * /* parm
return CURLE_SSL_CACERT_BADFILE;
}
- const auto pem = util::make_unique<char[]>(stat.size);
+ const auto pem = std::make_unique<char[]>(stat.size);
if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(pem.get()), stat.size)) != stat.size) {
zip_fclose(apkFile);
@@ -537,7 +537,7 @@ size_t HTTPRequest::writeCallback(void *const contents, const size_t size, const
MBGL_VERIFY_THREAD(impl->tid);
if (!impl->response) {
- impl->response = util::make_unique<Response>();
+ impl->response = std::make_unique<Response>();
}
impl->response->data.append((char *)contents, size * nmemb);
@@ -581,7 +581,7 @@ size_t HTTPRequest::headerCallback(char *const buffer, const size_t size, const
MBGL_VERIFY_THREAD(baton->tid);
if (!baton->response) {
- baton->response = util::make_unique<Response>();
+ baton->response = std::make_unique<Response>();
}
const size_t length = size * nmemb;
@@ -675,7 +675,7 @@ void HTTPRequest::handleResult(CURLcode code) {
// Make sure a response object exists in case we haven't got any headers
// or content.
if (!response) {
- response = util::make_unique<Response>();
+ response = std::make_unique<Response>();
}
// Add human-readable error code
@@ -734,7 +734,7 @@ void HTTPRequest::handleResult(CURLcode code) {
}
std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
- return util::make_unique<HTTPCURLContext>(loop);
+ return std::make_unique<HTTPCURLContext>(loop);
}
}
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index 1a10d78ffa..12aea898c8 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -1,7 +1,6 @@
#include <mbgl/util/image.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/util/std.hpp>
#include <png.h>
@@ -82,7 +81,7 @@ Image::Image(std::string const& data)
auto reader = getImageReader(data.c_str(), data.size());
width = reader->width();
height = reader->height();
- img = util::make_unique<char[]>(width * height * 4);
+ img = std::make_unique<char[]>(width * height * 4);
reader->read(0, 0, width, height, img.get());
}
catch (ImageReaderException const& ex)
diff --git a/platform/default/image_reader.cpp b/platform/default/image_reader.cpp
index fc6daec6a5..e80ccb6819 100644
--- a/platform/default/image_reader.cpp
+++ b/platform/default/image_reader.cpp
@@ -49,11 +49,11 @@ std::unique_ptr<ImageReader> getImageReader(char const* data, size_t size)
{
if (*type == "png")
{
- return util::make_unique<PngReader<boost::iostreams::array_source>>(data, size);
+ return std::make_unique<PngReader<boost::iostreams::array_source>>(data, size);
}
else if (*type == "jpeg")
{
- return util::make_unique<JpegReader<boost::iostreams::array_source>>(data, size);
+ return std::make_unique<JpegReader<boost::iostreams::array_source>>(data, size);
}
}
throw ImageReaderException("ImageReader: can't determine type from input data");
diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp
index fb4cdf74e7..06d168ce4e 100644
--- a/platform/default/sqlite_cache.cpp
+++ b/platform/default/sqlite_cache.cpp
@@ -62,7 +62,7 @@ std::string unifyMapboxURLs(const std::string &url) {
using namespace mapbox::sqlite;
SQLiteCache::SQLiteCache(const std::string& path_)
- : thread(util::make_unique<util::Thread<Impl>>("SQLite Cache", util::ThreadPriority::Low, path_)) {
+ : thread(std::make_unique<util::Thread<Impl>>("SQLite Cache", util::ThreadPriority::Low, path_)) {
}
SQLiteCache::~SQLiteCache() = default;
@@ -85,7 +85,7 @@ SQLiteCache::Impl::~Impl() {
}
void SQLiteCache::Impl::createDatabase() {
- db = util::make_unique<Database>(path.c_str(), ReadWrite | Create);
+ db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
}
void SQLiteCache::Impl::createSchema() {
@@ -114,7 +114,7 @@ void SQLiteCache::Impl::createSchema() {
} catch (util::IOException& ioEx) {
Log::Error(Event::Database, ex.code, ex.what());
}
- db = util::make_unique<Database>(path.c_str(), ReadWrite | Create);
+ db = std::make_unique<Database>(path.c_str(), ReadWrite | Create);
} else {
Log::Error(Event::Database, ex.code, ex.what());
}
@@ -146,8 +146,8 @@ std::unique_ptr<Response> SQLiteCache::Impl::get(const Resource &resource) {
}
if (!getStmt) {
- // Initialize the statement 0 1
- getStmt = util::make_unique<Statement>(db->prepare("SELECT `status`, `modified`, "
+ // Initialize the statement 0 1
+ getStmt = std::make_unique<Statement>(db->prepare("SELECT `status`, `modified`, "
// 2 3 4 5 1
"`etag`, `expires`, `data`, `compressed` FROM `http_cache` WHERE `url` = ?"));
} else {
@@ -158,7 +158,7 @@ std::unique_ptr<Response> SQLiteCache::Impl::get(const Resource &resource) {
getStmt->bind(1, unifiedURL.c_str());
if (getStmt->run()) {
// There is data.
- auto response = util::make_unique<Response>();
+ auto response = std::make_unique<Response>();
response->status = Response::Status(getStmt->get<int>(0));
response->modified = getStmt->get<int64_t>(1);
response->etag = getStmt->get<std::string>(2);
@@ -200,7 +200,7 @@ void SQLiteCache::Impl::put(const Resource& resource, std::shared_ptr<const Resp
}
if (!putStmt) {
- putStmt = util::make_unique<Statement>(db->prepare("REPLACE INTO `http_cache` ("
+ putStmt = std::make_unique<Statement>(db->prepare("REPLACE INTO `http_cache` ("
// 1 2 3 4 5 6 7 8
"`url`, `status`, `kind`, `modified`, `etag`, `expires`, `data`, `compressed`"
") VALUES(?, ?, ?, ?, ?, ?, ?, ?)"));
@@ -249,7 +249,7 @@ void SQLiteCache::Impl::refresh(const Resource& resource, int64_t expires) {
}
if (!refreshStmt) {
- refreshStmt = util::make_unique<Statement>( // 1 2
+ refreshStmt = std::make_unique<Statement>( // 1 2
db->prepare("UPDATE `http_cache` SET `expires` = ? WHERE `url` = ?"));
} else {
refreshStmt->reset();
diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m
index a49433777d..71987786c9 100644
--- a/platform/ios/MGLAccountManager.m
+++ b/platform/ios/MGLAccountManager.m
@@ -1,6 +1,6 @@
#import <Foundation/Foundation.h>
-#import "MGLAccountManager.h"
+#import "MGLAccountManager_Private.h"
#import "MGLMapboxEvents.h"
#import "NSProcessInfo+MGLAdditions.h"
@@ -14,6 +14,18 @@
@implementation MGLAccountManager
++ (void)load {
+ // 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.
//
+ (instancetype) sharedManager {
@@ -25,7 +37,6 @@
void (^setupBlock)() = ^{
dispatch_once(&onceToken, ^{
_sharedManager = [[self alloc] init];
- _sharedManager.mapboxMetricsEnabledSettingShownInApp = NO;
});
};
if ( ! [[NSThread currentThread] isMainThread]) {
@@ -39,16 +50,14 @@
return _sharedManager;
}
-+ (void) setMapboxMetricsEnabledSettingShownInApp:(BOOL)shown {
- [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = shown;
-}
-
+ (BOOL) mapboxMetricsEnabledSettingShownInApp {
return [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp;
}
+ (void) setAccessToken:(NSString *) accessToken {
- [[MGLAccountManager sharedManager] setAccessToken:accessToken];
+ if ( ! [accessToken length]) return;
+
+ [MGLAccountManager sharedManager].accessToken = accessToken;
// Update MGLMapboxEvents
// NOTE: This is (likely) the initial setup of MGLMapboxEvents
diff --git a/platform/ios/MGLAccountManager_Private.h b/platform/ios/MGLAccountManager_Private.h
new file mode 100644
index 0000000000..3cc05b09f0
--- /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 5d14107518..a517a4d26f 100644
--- a/platform/ios/MGLMapView.mm
+++ b/platform/ios/MGLMapView.mm
@@ -24,6 +24,7 @@
#import "MGLUserLocationAnnotationView.h"
#import "MGLUserLocation_Private.h"
#import "MGLFileCache.h"
+#import "MGLAccountManager_Private.h"
#import "MGLMapboxEvents.h"
#import "SMCalloutView.h"
@@ -35,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};
@@ -48,6 +49,16 @@ static NSURL *MGLURLForBundledStyleNamed(NSString *styleName)
return [NSURL URLWithString:[NSString stringWithFormat:@"asset://styles/%@.json", styleName]];
}
+CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees)
+{
+ return degrees * M_PI / 180;
+}
+
+CLLocationDegrees MGLDegreesFromRadians(CGFloat radians)
+{
+ return radians * 180 / M_PI;
+}
+
#pragma mark - Private -
@interface MGLMapView () <UIGestureRecognizerDelegate, GLKViewDelegate, CLLocationManagerDelegate, UIActionSheetDelegate>
@@ -103,63 +114,48 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
- (instancetype)initWithFrame:(CGRect)frame
{
- self = [super initWithFrame:frame];
-
- if (self && [self commonInit])
+ if (self = [super initWithFrame:frame])
{
+ [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];
+ return self;
}
-- (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])
+ if (self = [super initWithFrame:frame])
{
- self.accessToken = accessToken;
+ [self commonInit];
self.styleURL = styleURL;
}
-
return self;
}
- (instancetype)initWithCoder:(NSCoder *)decoder
{
- self = [super initWithCoder:decoder];
-
- if (self && [self commonInit])
+ if (self = [super initWithCoder:decoder])
{
+ [self commonInit];
self.styleURL = nil;
- return self;
}
-
- return nil;
+ return self;
}
- (NSString *)accessToken
{
- return @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty;
+ 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 setWithObject:@"styleID"];
}
- (NSURL *)styleURL
@@ -188,20 +184,14 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
_mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]);
}
-- (BOOL)commonInit
+- (void)commonInit
{
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
// create context
//
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
-
- if ( ! _context)
- {
- mbgl::Log::Error(mbgl::Event::Setup, "failed to create OpenGL ES context");
-
- return NO;
- }
+ NSAssert(_context, @"Failed to create OpenGL ES context.");
// setup accessibility
//
@@ -253,13 +243,20 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
}
_mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor);
+ // 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
selector:@selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
- Reachability* reachability = [Reachability reachabilityForInternetConnection];
+ MGLReachability* reachability = [MGLReachability reachabilityForInternetConnection];
[reachability startNotifier];
// setup annotations
@@ -294,6 +291,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"]];
@@ -376,13 +379,11 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
MGLEventKeyZoomLevel: @(zoom),
MGLEventKeyPushEnabled: @([MGLMapboxEvents checkPushEnabled])
}];
-
- return YES;
}
-(void)reachabilityChanged:(NSNotification*)notification
{
- Reachability *reachability = [notification object];
+ MGLReachability *reachability = [notification object];
if ([reachability isReachable]) {
mbgl::NetworkStatus::Reachable();
}
@@ -393,6 +394,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
[_regionChangeDelegateQueue cancelAllOperations];
[[NSNotificationCenter defaultCenter] removeObserver:self];
+ [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"];
if (_mbglMap)
{
@@ -905,13 +907,13 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
_mbglMap->setGestureInProgress(true);
- self.angle = [MGLMapView degreesToRadians:_mbglMap->getBearing()] * -1;
+ self.angle = MGLRadiansFromDegrees(_mbglMap->getBearing()) * -1;
self.userTrackingMode = MGLUserTrackingModeNone;
}
else if (rotate.state == UIGestureRecognizerStateChanged)
{
- CGFloat newDegrees = [MGLMapView radiansToDegrees:(self.angle + rotate.rotation)] * -1;
+ CGFloat newDegrees = MGLDegreesFromRadians(self.angle + rotate.rotation) * -1;
// constrain to +/-30 degrees when merely rotating like Apple does
//
@@ -934,7 +936,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
CGFloat radians = self.angle + rotate.rotation;
CGFloat duration = UIScrollViewDecelerationRateNormal;
CGFloat newRadians = radians + velocity * duration * 0.1;
- CGFloat newDegrees = [MGLMapView radiansToDegrees:newRadians] * -1;
+ CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;
_mbglMap->setBearing(newDegrees, secondsAsDuration(duration));
@@ -999,16 +1001,16 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
mbgl::LatLngBounds tapBounds;
coordinate = [self convertPoint:tapRectLowerLeft toCoordinateFromView:self];
- tapBounds.extend(coordinateToLatLng(coordinate));
+ tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
coordinate = [self convertPoint:tapRectUpperLeft toCoordinateFromView:self];
- tapBounds.extend(coordinateToLatLng(coordinate));
+ tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
coordinate = [self convertPoint:tapRectUpperRight toCoordinateFromView:self];
- tapBounds.extend(coordinateToLatLng(coordinate));
+ tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
coordinate = [self convertPoint:tapRectLowerRight toCoordinateFromView:self];
- tapBounds.extend(coordinateToLatLng(coordinate));
+ tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
// query for nearby annotations
std::vector<uint32_t> nearbyAnnotations = _mbglMap->getAnnotationsInBounds(tapBounds);
@@ -1270,10 +1272,25 @@ 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 -
+- (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];
+ _mbglFileSource->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : "");
+ }
+}
+
+ (NSSet *)keyPathsForValuesAffectingZoomEnabled
{
return [NSSet setWithObject:@"allowsZooming"];
@@ -1361,7 +1378,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
{
CGFloat duration = (animated ? MGLAnimationDuration : 0);
- _mbglMap->setLatLngZoom(coordinateToLatLng(coordinate),
+ _mbglMap->setLatLngZoom(MGLLatLngFromLocationCoordinate2D(coordinate),
fmaxf(_mbglMap->getZoom(), self.currentMinimumZoom),
secondsAsDuration(duration));
@@ -1375,7 +1392,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
- (CLLocationCoordinate2D)centerCoordinate
{
- return latLngToCoordinate(_mbglMap->getLatLng());
+ return MGLLocationCoordinate2DFromLatLng(_mbglMap->getLatLng());
}
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel animated:(BOOL)animated
@@ -1384,7 +1401,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
CGFloat duration = (animated ? MGLAnimationDuration : 0);
- _mbglMap->setLatLngZoom(coordinateToLatLng(centerCoordinate), zoomLevel, secondsAsDuration(duration));
+ _mbglMap->setLatLngZoom(MGLLatLngFromLocationCoordinate2D(centerCoordinate), zoomLevel, secondsAsDuration(duration));
[self unrotateIfNeededAnimated:animated];
@@ -1468,12 +1485,12 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
//
convertedPoint.y = self.bounds.size.height - convertedPoint.y;
- return latLngToCoordinate(_mbglMap->latLngForPixel(mbgl::vec2<double>(convertedPoint.x, convertedPoint.y)));
+ return MGLLocationCoordinate2DFromLatLng(_mbglMap->latLngForPixel(mbgl::vec2<double>(convertedPoint.x, convertedPoint.y)));
}
- (CGPoint)convertCoordinate:(CLLocationCoordinate2D)coordinate toPointToView:(UIView *)view
{
- mbgl::vec2<double> pixel = _mbglMap->pixelForLatLng(coordinateToLatLng(coordinate));
+ mbgl::vec2<double> pixel = _mbglMap->pixelForLatLng(MGLLatLngFromLocationCoordinate2D(coordinate));
// flip y coordinate for iOS view origin in top left
//
@@ -1487,12 +1504,12 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
return _mbglMap->getMetersPerPixelAtLatitude(latitude, self.zoomLevel);
}
-mbgl::LatLng coordinateToLatLng(CLLocationCoordinate2D coordinate)
+mbgl::LatLng MGLLatLngFromLocationCoordinate2D(CLLocationCoordinate2D coordinate)
{
return mbgl::LatLng(coordinate.latitude, coordinate.longitude);
}
-CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
+CLLocationCoordinate2D MGLLocationCoordinate2DFromLatLng(mbgl::LatLng latLng)
{
return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude);
}
@@ -1501,13 +1518,13 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
{
mbgl::LatLngBounds bounds;
- bounds.extend(coordinateToLatLng(
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(
[self convertPoint:CGPointMake(0, 0) toCoordinateFromView:self]));
- bounds.extend(coordinateToLatLng(
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(
[self convertPoint:CGPointMake(self.bounds.size.width, 0) toCoordinateFromView:self]));
- bounds.extend(coordinateToLatLng(
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(
[self convertPoint:CGPointMake(0, self.bounds.size.height) toCoordinateFromView:self]));
- bounds.extend(coordinateToLatLng(
+ bounds.extend(MGLLatLngFromLocationCoordinate2D(
[self convertPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height) toCoordinateFromView:self]));
return bounds;
@@ -1533,27 +1550,31 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
return [NSArray arrayWithArray:_bundledStyleURLs];
}
-+ (NSSet *)keyPathsForValuesAffectingMapID
++ (NSSet *)keyPathsForValuesAffectingStyleID
{
- return [NSSet setWithObjects:@"styleURL", @"accessToken", nil];
+ return [NSSet setWithObject:@"styleURL"];
}
-- (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
@@ -1657,7 +1678,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
{
assert([annotation conformsToProtocol:@protocol(MGLAnnotation)]);
- latLngs.push_back(coordinateToLatLng(annotation.coordinate));
+ latLngs.push_back(MGLLatLngFromLocationCoordinate2D(annotation.coordinate));
NSString *symbolName = nil;
@@ -1726,7 +1747,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
assert([firstAnnotation conformsToProtocol:@protocol(MGLAnnotation)]);
- if ( ! [self viewportBounds].contains(coordinateToLatLng(firstAnnotation.coordinate))) return;
+ if ( ! [self viewportBounds].contains(MGLLatLngFromLocationCoordinate2D(firstAnnotation.coordinate))) return;
[self selectAnnotation:firstAnnotation animated:NO];
}
@@ -1735,7 +1756,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
{
if ( ! annotation) return;
- if ( ! [self viewportBounds].contains(coordinateToLatLng(annotation.coordinate))) return;
+ if ( ! [self viewportBounds].contains(MGLLatLngFromLocationCoordinate2D(annotation.coordinate))) return;
if (annotation == self.selectedAnnotation) return;
@@ -2171,16 +2192,6 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
#pragma mark - Utility -
-+ (CGFloat)degreesToRadians:(CGFloat)degrees
-{
- return degrees * M_PI / 180;
-}
-
-+ (CGFloat)radiansToDegrees:(CGFloat)radians
-{
- return radians * 180 / M_PI;
-}
-
- (void)animateWithDelay:(NSTimeInterval)delay animations:(void (^)(void))animations
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), animations);
@@ -2398,7 +2409,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
while (degrees >= 360) degrees -= 360;
while (degrees < 0) degrees += 360;
- self.compass.transform = CGAffineTransformMakeRotation([MGLMapView degreesToRadians:degrees]);
+ self.compass.transform = CGAffineTransformMakeRotation(MGLRadiansFromDegrees(degrees));
if (_mbglMap->getBearing() && self.compass.alpha < 1)
{
@@ -2431,14 +2442,14 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
imageName = [imageName stringByAppendingString:@".png"];
}
- return [UIImage imageWithContentsOfFile:[MGLMapView pathForBundleResourceNamed:imageName ofType:nil inDirectory:@""]];
+ return [UIImage imageWithContentsOfFile:[self pathForBundleResourceNamed:imageName ofType:nil inDirectory:@""]];
}
+ (NSString *)pathForBundleResourceNamed:(NSString *)name ofType:(NSString *)extension inDirectory:(NSString *)directory
{
NSString *path = [[NSBundle bundleWithPath:[NSBundle mgl_resourceBundlePath]] pathForResource:name ofType:extension inDirectory:directory];
- NSAssert(path, @"Resource not found in application.");
+ NSAssert(path, @"Resource %@ not found in application.", name);
return path;
}
@@ -2461,129 +2472,106 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
{
[super prepareForInterfaceBuilder];
- self.layer.borderColor = [UIColor colorWithWhite:184/255. alpha:1].CGColor;
- self.layer.borderWidth = 1;
-
- if (self.accessToken)
- {
- self.layer.backgroundColor = [UIColor colorWithRed:59/255.
- green:178/255.
- blue:208/255.
- alpha:0.8].CGColor;
-
- 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 = @"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 map here, you must provide a Mapbox 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:MGLMapboxAccessTokenManagerURLDisplayString forState:UIControlStateNormal];
- linkButton.translatesAutoresizingMaskIntoConstraints = NO;
- [linkButton setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
- forAxis:UILayoutConstraintAxisHorizontal];
- [diagnosticView addSubview:linkButton];
-
- // More explanation
- UILabel *explanationLabel2 = [[UILabel alloc] init];
- explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector.";
- 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]];
- }
+ 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;
+
+ 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];
+
+ // 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];
+
+ // 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];
+
+ // 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
diff --git a/platform/ios/MGLMapboxEvents.h b/platform/ios/MGLMapboxEvents.h
index 94aa8be783..00de64a8b0 100644
--- a/platform/ios/MGLMapboxEvents.h
+++ b/platform/ios/MGLMapboxEvents.h
@@ -1,5 +1,6 @@
#import <Foundation/Foundation.h>
+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 98bfe21cfe..e7f400c5dc 100644
--- a/platform/ios/MGLMapboxEvents.m
+++ b/platform/ios/MGLMapboxEvents.m
@@ -13,9 +13,11 @@
#include <sys/sysctl.h>
+static const NSUInteger version = 1;
static NSString *const MGLMapboxEventsUserAgent = @"MapboxEventsiOS/1.0";
static NSString *MGLMapboxEventsAPIBase = @"https://api.tiles.mapbox.com";
+NSString *const MGLEventTypeAppUserTurnstile = @"appUserTurnstile";
NSString *const MGLEventTypeMapLoad = @"map.load";
NSString *const MGLEventTypeMapTap = @"map.click";
NSString *const MGLEventTypeMapDragEnd = @"map.dragend";
@@ -52,7 +54,6 @@ const NSTimeInterval MGLFlushInterval = 60;
// All of the following properties are written to only from
// the main thread, but can be read on any thread.
//
-@property (atomic) NSString *instanceID;
@property (atomic) NSString *advertiserId;
@property (atomic) NSString *vendorId;
@property (atomic) NSString *model;
@@ -66,8 +67,7 @@ const NSTimeInterval MGLFlushInterval = 60;
- (instancetype)init {
if (self = [super init]) {
- _instanceID = [[NSUUID UUID] UUIDString];
-
+
// Dynamic detection of ASIdentifierManager from Mixpanel
// https://github.com/mixpanel/mixpanel-iphone/blob/master/LICENSE
_advertiserId = @"";
@@ -143,6 +143,7 @@ const NSTimeInterval MGLFlushInterval = 60;
@property (atomic) NSString *appName;
@property (atomic) NSString *appVersion;
@property (atomic) NSString *appBuildNumber;
+@property (atomic) NSString *instanceID;
@property (atomic) NSDateFormatter *rfc3339DateFormatter;
@property (atomic) NSURLSession *session;
@property (atomic) NSData *digicertCert;
@@ -176,8 +177,10 @@ const NSTimeInterval MGLFlushInterval = 60;
+ (void)initialize {
if (self == [MGLMapboxEvents class]) {
+ NSBundle *bundle = [NSBundle mainBundle];
+ NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccountType"];
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
- @"MGLMapboxAccountType": @0,
+ @"MGLMapboxAccountType": accountTypeNumber ? accountTypeNumber : @0,
@"MGLMapboxMetricsEnabled": @YES,
}];
}
@@ -195,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;
@@ -213,7 +217,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,
}];
@@ -223,7 +227,8 @@ const NSTimeInterval MGLFlushInterval = 60;
_appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
_appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
_appBuildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
-
+ _instanceID = [[NSUUID UUID] UUIDString];
+
NSString *uniqueID = [[NSProcessInfo processInfo] globallyUniqueString];
_serialQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@.%@.events.serial", _appBundleId, uniqueID] UTF8String], DISPATCH_QUEUE_SERIAL);
@@ -277,6 +282,11 @@ const NSTimeInterval MGLFlushInterval = 60;
MGLMapboxEvents *strongSelf = weakSelf;
[strongSelf validate];
}];
+
+ // Turn the Mapbox Turnstile to Count App Users
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+ [self pushTurnstileEvent];
+ });
}
return self;
}
@@ -315,6 +325,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];
@@ -414,6 +425,33 @@ 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,
+ @"version": @(version),
+ @"instance": strongSelf.instanceID};
+
+ // Add to Queue
+ [_eventQueue addObject:vevt];
+
+ // Flush
+ [strongSelf flush];
+ });
+}
+
// Can be called from any thread. Can be called rapidly from
// the UI thread, so performance is paramount.
//
@@ -430,9 +468,11 @@ const NSTimeInterval MGLFlushInterval = 60;
__weak MGLMapboxEvents *weakSelf = self;
dispatch_async(_serialQueue, ^{
+
MGLMapboxEvents *strongSelf = weakSelf;
+
if ( ! strongSelf) return;
-
+
// Metrics Collection Has Been Paused
if (_paused) {
return;
@@ -443,9 +483,9 @@ const NSTimeInterval MGLFlushInterval = 60;
NSMutableDictionary *evt = [[NSMutableDictionary alloc] initWithDictionary:attributeDictionary];
// mapbox-events stock attributes
[evt setObject:event forKey:@"event"];
- [evt setObject:@(1) forKey:@"version"];
+ [evt setObject:@(version) forKey:@"version"];
[evt setObject:[strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"created"];
- [evt setObject:strongSelf.data.instanceID forKey:@"instance"];
+ [evt setObject:strongSelf.instanceID forKey:@"instance"];
[evt setObject:strongSelf.data.advertiserId forKey:@"advertiserId"];
[evt setObject:strongSelf.data.vendorId forKey:@"vendorId"];
[evt setObject:strongSelf.appBundleId forKeyedSubscript:@"appBundleId"];