diff --git a/plugin.xml b/plugin.xml index c2cd076..753d4ee 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,7 +1,7 @@ + version="1.7.3"> DataCollection Background data collection FTW! This is the part that I really diff --git a/src/ios/BEMDataCollection.m b/src/ios/BEMDataCollection.m index ba5510a..6ba295b 100644 --- a/src/ios/BEMDataCollection.m +++ b/src/ios/BEMDataCollection.m @@ -7,6 +7,7 @@ #import "StatsEvent.h" #import "BEMBuiltinUserCache.h" #import "SensorControlForegroundDelegate.h" +#import "SensorControlBackgroundChecker.h" #import @implementation BEMDataCollection @@ -46,6 +47,7 @@ - (id)settingForKey:(NSString*)key - (void)initWithConsent { self.tripDiaryStateMachine = [TripDiaryStateMachine instance]; + [SensorControlBackgroundChecker checkAppState]; NSDictionary* emptyOptions = @{}; [AppDelegate didFinishLaunchingWithOptions:emptyOptions]; } diff --git a/src/ios/ConfigManager.h b/src/ios/ConfigManager.h index 60f52c7..ba0baa4 100644 --- a/src/ios/ConfigManager.h +++ b/src/ios/ConfigManager.h @@ -14,6 +14,7 @@ + (LocationTrackingConfig*) instance; + (void) updateConfig:(LocationTrackingConfig*) newConfig; ++ (ConsentConfig*) getPriorConsent; + (BOOL) isConsented:(NSString*)reqConsent; + (void) setConsented:(ConsentConfig*) newConfig; @end diff --git a/src/ios/ConfigManager.m b/src/ios/ConfigManager.m index 8a4bc43..1063530 100644 --- a/src/ios/ConfigManager.m +++ b/src/ios/ConfigManager.m @@ -45,6 +45,12 @@ + (void) updateConfig:(LocationTrackingConfig*) newConfig { _instance = newConfig; } ++ (ConsentConfig*) getPriorConsent { + ConsentConfig* currConfig = (ConsentConfig*)[[BuiltinUserCache database] getDocument:CONSENT_CONFIG_KEY wrapperClass:[ConsentConfig class]]; + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"in getPriorConsent, currConfig = %@", currConfig]]; + return currConfig; +} + + (BOOL) isConsented:(NSString*)reqConsent { @try { ConsentConfig* currConfig = (ConsentConfig*)[[BuiltinUserCache database] getDocument:CONSENT_CONFIG_KEY wrapperClass:[ConsentConfig class]]; diff --git a/src/ios/Location/TripDiaryStateMachine.m b/src/ios/Location/TripDiaryStateMachine.m index a49b643..20a482f 100644 --- a/src/ios/Location/TripDiaryStateMachine.m +++ b/src/ios/Location/TripDiaryStateMachine.m @@ -87,7 +87,9 @@ - (id) init { _geofenceLocator = [GeofenceActions new]; // The operations in the one time init tracking are idempotent, so let's start them anyway - [TripDiaryActions oneTimeInitTracking:CFCTransitionInitialize withLocationMgr:self.locMgr]; + if ([ConfigManager getPriorConsent] != NULL) { + [TripDiaryActions oneTimeInitTracking:CFCTransitionInitialize withLocationMgr:self.locMgr]; + } [LocalNotificationManager addNotification:[NSString stringWithFormat: @"initializing TripDiaryStateMachine with state = %@", @@ -104,38 +106,10 @@ - (id) init { // would be good to test, though. } - // STATUS SCREEN: Figure out how to fix recursion when [TripDiaryStateMachine instance] is called - // [SensorControlBackgroundChecker checkAppState]; - /* The only times we should get here are: - * - if we re-install a previously installed app, and so it is already authorized for background location collection BUT is in the start state, or - * - another option might be a re-launch of the app when the user has manually stopped tracking. - * It would be bad to automatically restart the tracking if the user has manully stopped tracking. - * One way to deal with this would be to have separate states for "start" and for "tracking suspended". - * Another way would be to just remove this transition from here... - * TODO: Figure out how to deal with it. - */ - // STATUS SCREEN: Figure out how to fix recursion when [TripDiaryStateMachine instance] is called - // [SensorControlBackgroundChecker restartFSMIfStartState]; - /* - if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways) { - [TripDiarySettingsCheck promptForPermission:self.locMgr]; - } else { - NSLog(@"Current location authorization = %d, always = %d", - [CLLocationManager authorizationStatus], kCLAuthorizationStatusAuthorizedAlways); - The only times we should get here are: - * - if we re-install a previously installed app, and so it is already authorized for background location collection BUT is in the start state, or - * - another option might be a re-launch of the app when the user has manually stopped tracking. - * It would be bad to automatically restart the tracking if the user has manully stopped tracking. - * One way to deal with this would be to have separate states for "start" and for "tracking suspended". - * Another way would be to just remove this transition from here... - * TODO: Figure out how to deal with it. - - if (self.currState == kStartState) { - [[NSNotificationCenter defaultCenter] postNotificationName:CFCTransitionNotificationName - object:CFCTransitionInitialize]; - } - } - */ + // Replaced by a call to [SensorControlBackgroundChecker checkAppState] + // just after the initialization is complete in the background + // currently only in `BEMDataCollection initWithConsent` + // https://github.com/e-mission/e-mission-docs/issues/735#issuecomment-1179774103 if (![ConfigManager instance].is_duty_cycling && self.currState != kTrackingStoppedState) { /* If we are not using geofencing, and the tracking is not manually turned off, then we don't need to listen diff --git a/src/ios/Verification/SensorControlBackgroundChecker.m b/src/ios/Verification/SensorControlBackgroundChecker.m index 51aad2a..8c36e50 100644 --- a/src/ios/Verification/SensorControlBackgroundChecker.m +++ b/src/ios/Verification/SensorControlBackgroundChecker.m @@ -4,6 +4,7 @@ #import "LocalNotificationManager.h" #import "BEMAppDelegate.h" #import "BEMActivitySync.h" +#import "ConfigManager.h" #import #define OPEN_APP_STATUS_PAGE_ID @362253744 @@ -60,26 +61,24 @@ +(void)checkAppState [LocalNotificationManager addNotification:[NSString stringWithFormat:@"All settings valid, nothing to prompt"]]; [self restartFSMIfStartState]; } - else if (locChecksPass) { - /* - Log.i(ctxt, TAG, "all checks = "+allOtherChecksPass+" but location permission status "+allOtherChecks[0]+" should be true "+ - " so one of the non-location checks must be false: loc permission, motion permission, notification, unused apps" + Arrays.toString(allOtherChecks)); - Log.i(ctxt, TAG, "a non-local check failed, generating only user visible notification"); - */ - [self generateOpenAppSettingsNotification]; - } else { - /* - Log.i(ctxt, TAG, "location settings are valid, but location permission is not, generating tracking error and visible notification"); - Log.i(ctxt, TAG, "curr status check results = " + - " loc permission, motion permission, notification, unused apps "+ Arrays.toString(allOtherChecks)); - */ - // Should replace with TRACKING_ERROR but looks like we - // don't have any - [[NSNotificationCenter defaultCenter] - postNotificationName:CFCTransitionNotificationName - object:CFCTransitionGeofenceCreationError]; - [self generateOpenAppSettingsNotification]; + if ([ConfigManager getPriorConsent] == NULL) { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"User has not yet consented, ignoring failed checks"]]; + } else { + if (locChecksPass) { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"allChecksPass = %@, but location permimssions pass, so one of the non-location checks must be false: [loc settings, loc permissions, motion settings, motion permissions, notification] = %@", @(allChecksPass), allChecks]]; + [self generateOpenAppSettingsNotification]; + } + else { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"allChecksPass = %@, but location checks fail, generating error and notification, allChecks: [loc settings, loc permissions, motion settings, motion permissions, notification] = %@", @(allChecksPass), allChecks]]; + // Should replace with TRACKING_ERROR but looks like we + // don't have any + [[NSNotificationCenter defaultCenter] + postNotificationName:CFCTransitionNotificationName + object:CFCTransitionGeofenceCreationError]; + [self generateOpenAppSettingsNotification]; + } + } } } diff --git a/src/ios/Verification/SensorControlForegroundDelegate.m b/src/ios/Verification/SensorControlForegroundDelegate.m index 22f9af0..62eba0e 100644 --- a/src/ios/Verification/SensorControlForegroundDelegate.m +++ b/src/ios/Verification/SensorControlForegroundDelegate.m @@ -143,14 +143,18 @@ -(void) checkAndPromptLocationPermissions - (void) didChangeAuthorizationStatus:(CLAuthorizationStatus)status { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"In delegate didChangeAuthorizationStatus, newStatus = %d", status]]; [[TripDiaryStateMachine instance].locMgr stopUpdatingLocation]; NSString* callbackId = [command callbackId]; @try { if (status == kCLAuthorizationStatusAuthorizedAlways) { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"status == always, restarting FSM if start state"]]; + [SensorControlBackgroundChecker restartFSMIfStartState]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; [commandDelegate sendPluginResult:result callbackId:callbackId]; } else { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"status %d != always %d, returning error", status, kCLAuthorizationStatusAuthorizedAlways]]; NSString* msg = NSLocalizedStringFromTable(@"location_permission_off_app_open", @"DCLocalizable", nil); CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR @@ -340,13 +344,16 @@ - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { [LocalNotificationManager addNotification:[NSString stringWithFormat:@"In checker's didChangeAuthorizationStatus, new authorization status = %d, always = %d", status, kCLAuthorizationStatusAuthorizedAlways]]; - [LocalNotificationManager addNotification:[NSString stringWithFormat:@"Calling TripDiarySettingsCheck from didChangeAuthorizationStatus to verify location service status and permission"]]; if (foregroundDelegateList.count > 0) { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"%lu foreground delegates found, calling didChangeAuthorizationStatus to return the new value %d", (unsigned long)foregroundDelegateList.count, status]]; + for (id currDelegate in foregroundDelegateList) { [currDelegate didChangeAuthorizationStatus:(CLAuthorizationStatus)status]; } + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"Notified all foreground delegates, removing all of them"]]; [foregroundDelegateList removeAllObjects]; } else { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"No foreground delegate found, calling SensorControlBackgroundChecker from didChangeAuthorizationStatus to verify location service status and permission"]]; [SensorControlBackgroundChecker checkAppState]; } }