summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Bounds <jesse@rebounds.net>2017-12-27 12:01:39 -0800
committerJesse Bounds <jesse@rebounds.net>2018-01-03 14:25:27 -0800
commitef11b99965ab8f75b63e17745070ef12a12a9e80 (patch)
tree3f7aeea3a42028a69dff9c59387d86a8047147fe
parent760ef23ac3faf4437cadb52983383c9501336964 (diff)
downloadqtlocation-mapboxgl-upstream/boundsj-dispatch-location-auth-status-check.tar.gz
[ios] Dispatch location auth status check to backgroundupstream/boundsj-dispatch-location-auth-status-check
This attempts to work around reports of repeated calls to [CLLocationManager authorizationStatus] blocking the main thread by dispatching it to the background, serial queue that is already available in MGLMapboxEvents. This also adds a guard to the handler for the user defaults change event so that the call to pause or resume if required is done only if a user defaults value changes that would require an update to the pause / resume state. The guard works by utilizing two new state variables that keep track of the previous values for account type and metrics enabled configuration variables. The call to pause/resume is only done if the latest relevant values in the user defaults dictionary are actually different than the previous ones. The default values for the new state variables assume an account value of 0 and metrics enabled == true so there can be a small inefficiency if a user prevously opted out of telemetry, kills the app, and restarts it. In that case, the pause/resume method would get invoked one time when it would not technically need to. This should not be an issue in practice though.
-rw-r--r--platform/ios/src/MGLMapboxEvents.m103
1 files changed, 67 insertions, 36 deletions
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 4f1413d300..d59972f5bf 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -54,6 +54,9 @@ static NSString *const MGLEventKeySessionId = @"sessionId";
static NSString *const MGLEventKeyApplicationState = @"applicationState";
static NSString *const MGLEventKeyAltitude = @"altitude";
+static NSString *const MGLMapboxAccountType = @"MGLMapboxAccountType";
+static NSString *const MGLMapboxMetricsEnabled = @"MGLMapboxMetricsEnabled";
+
// SDK event source
static NSString *const MGLEventSource = @"mapbox";
@@ -124,6 +127,8 @@ const NSTimeInterval MGLFlushInterval = 180;
@property (nonatomic) NSTimer *timer;
@property (nonatomic) NSDate *instanceIDRotationDate;
@property (nonatomic) NSDate *nextTurnstileSendDate;
+@property (nonatomic) NSNumber *currentAccountTypeValue;
+@property (nonatomic) BOOL currentMetricsEnabledValue;
@end
@@ -135,10 +140,10 @@ const NSTimeInterval MGLFlushInterval = 180;
+ (void)initialize {
if (self == [MGLMapboxEvents class]) {
NSBundle *bundle = [NSBundle mainBundle];
- NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccountType"];
+ NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:MGLMapboxAccountType];
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
- @"MGLMapboxAccountType": accountTypeNumber ?: @0,
- @"MGLMapboxMetricsEnabled": @YES,
+ MGLMapboxAccountType: accountTypeNumber ?: @0,
+ MGLMapboxMetricsEnabled: @YES,
@"MGLMapboxMetricsDebugLoggingEnabled": @NO,
}];
}
@@ -152,8 +157,8 @@ const NSTimeInterval MGLFlushInterval = 180;
if ([NSProcessInfo instancesRespondToSelector:@selector(isLowPowerModeEnabled)]) {
isLowPowerModeEnabled = [[NSProcessInfo processInfo] isLowPowerModeEnabled];
}
- return ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"] &&
- [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0 &&
+ return ([[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabled] &&
+ [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType] == 0 &&
!isLowPowerModeEnabled);
#endif
}
@@ -167,6 +172,9 @@ const NSTimeInterval MGLFlushInterval = 180;
- (instancetype) init {
self = [super init];
if (self) {
+ _currentAccountTypeValue = @0;
+ _currentMetricsEnabledValue = YES;
+
_appBundleId = [[NSBundle mainBundle] bundleIdentifier];
_apiClient = [[MGLAPIClient alloc] init];
@@ -249,38 +257,61 @@ const NSTimeInterval MGLFlushInterval = 180;
}
- (void)userDefaultsDidChange:(NSNotification *)notification {
- dispatch_async(dispatch_get_main_queue(), ^{
- [self pauseOrResumeMetricsCollectionIfRequired];
- });
+
+ // Guard against over calling pause / resume if the values this implementation actually
+ // cares about have not changed
+
+ if ([[notification object] respondsToSelector:@selector(objectForKey:)]) {
+ NSUserDefaults *userDefaults = [notification object];
+
+ NSNumber *accountType = [userDefaults objectForKey:MGLMapboxAccountType];
+ BOOL metricsEnabled = [[userDefaults objectForKey:MGLMapboxMetricsEnabled] boolValue];
+
+ if (![accountType isEqualToNumber:self.currentAccountTypeValue] || metricsEnabled != self.currentMetricsEnabledValue) {
+ [self pauseOrResumeMetricsCollectionIfRequired];
+ self.currentAccountTypeValue = accountType;
+ self.currentMetricsEnabledValue = metricsEnabled;
+ }
+ }
+
}
- (void)pauseOrResumeMetricsCollectionIfRequired {
- UIApplication *application = [UIApplication sharedApplication];
-
- // Prevent blue status bar when host app has `when in use` permission only and it is not in foreground
- if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse &&
- application.applicationState == UIApplicationStateBackground) {
-
- if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
- _backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
- [application endBackgroundTask:_backgroundTaskIdentifier];
- _backgroundTaskIdentifier = UIBackgroundTaskInvalid;
- }];
- [self flush];
- }
-
- [self pauseMetricsCollection];
- return;
- }
-
- // Toggle pause based on current pause state, user opt-out state, and low-power state.
- BOOL enabled = [[self class] isEnabled];
- if (self.paused && enabled) {
- [self resumeMetricsCollection];
- } else if (!self.paused && !enabled) {
- [self flush];
- [self pauseMetricsCollection];
- }
+
+ // [CLLocationManager authorizationStatus] has been found to block in some cases so
+ // dispatch the call to a non-UI thread
+ dispatch_async(self.serialQueue, ^{
+ CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
+
+ // Checking application state must be done on the main thread for safety and
+ // to avoid a thread sanitizer error
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIApplication *application = [UIApplication sharedApplication];
+ UIApplicationState state = application.applicationState;
+
+ // Prevent blue status bar when host app has `when in use` permission only and it is not in foreground
+ if (status == kCLAuthorizationStatusAuthorizedWhenInUse && state == UIApplicationStateBackground) {
+ if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
+ _backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
+ [application endBackgroundTask:_backgroundTaskIdentifier];
+ _backgroundTaskIdentifier = UIBackgroundTaskInvalid;
+ }];
+ [self flush];
+ }
+ [self pauseMetricsCollection];
+ return;
+ }
+
+ // Toggle pause based on current pause state, user opt-out state, and low-power state.
+ BOOL enabled = [[self class] isEnabled];
+ if (self.paused && enabled) {
+ [self resumeMetricsCollection];
+ } else if (!self.paused && !enabled) {
+ [self flush];
+ [self pauseMetricsCollection];
+ }
+ });
+ });
}
- (void)pauseMetricsCollection {
@@ -602,7 +633,7 @@ const NSTimeInterval MGLFlushInterval = 180;
BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue];
if (!metricsEnabledSettingShownInAppFlag &&
- [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) {
+ [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType] == 0) {
// Opt-out is not configured in UI, so check for Settings.bundle
id defaultEnabledValue;
NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
@@ -612,7 +643,7 @@ const NSTimeInterval MGLFlushInterval = 180;
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSArray *preferences = settings[@"PreferenceSpecifiers"];
for (NSDictionary *prefSpecification in preferences) {
- if ([prefSpecification[@"Key"] isEqualToString:@"MGLMapboxMetricsEnabled"]) {
+ if ([prefSpecification[@"Key"] isEqualToString:MGLMapboxMetricsEnabled]) {
defaultEnabledValue = prefSpecification[@"DefaultValue"];
}
}