From 2fc078b93c443e03d15712bef81835fb8665bed2 Mon Sep 17 00:00:00 2001 From: Shankari Date: Thu, 10 Feb 2022 15:34:19 -0800 Subject: [PATCH] Initial implmentation of the status screen - End-to-end implementation of the "check" parts of the interface - Code structure similar to the existing android code for simplicity - checks defined in `TripDiarySensorControlChecks` - interface with the plugin in `SensorControlForegroundDelegate` - interface with the background code to generate error notifications in `SensorControlBackgroundChecker` Testing done: With the UI changes in: https://github.com/e-mission/e-mission-phone/pull/812/commits/d69f3a50bfacf52a63f5a0c134650831c6ad1962 the plugin -> foreground delegate -> checks pipeline works https://github.com/e-mission/e-mission-phone/pull/812#issuecomment-1035657284 TO DO: - Background checks need to be tested - Implement the "fix" methods in addition to the "check" methods --- plugin.xml | 8 +- res/ios/en.lproj/DCLocalizable.strings | 9 ++ src/ios/BEMDataCollection.m | 43 +++------ src/ios/BEMRemotePushNotificationHandler.h | 1 - src/ios/BEMRemotePushNotificationHandler.m | 20 +---- src/ios/Location/TripDiaryDelegate.m | 8 +- src/ios/Location/TripDiaryStateMachine.m | 26 ++++-- .../SensorControlBackgroundChecker.h | 11 +++ .../SensorControlBackgroundChecker.m | 90 +++++++++++++++++++ .../SensorControlForegroundDelegate.h | 15 ++++ .../SensorControlForegroundDelegate.m | 82 +++++++++++++++++ .../TripDiarySensorControlChecks.h | 8 +- .../TripDiarySensorControlChecks.m | 47 +++++++++- 13 files changed, 307 insertions(+), 61 deletions(-) create mode 100644 src/ios/Verification/SensorControlBackgroundChecker.h create mode 100644 src/ios/Verification/SensorControlBackgroundChecker.m create mode 100644 src/ios/Verification/SensorControlForegroundDelegate.h create mode 100644 src/ios/Verification/SensorControlForegroundDelegate.m diff --git a/plugin.xml b/plugin.xml index a4e862c5..63848d32 100644 --- a/plugin.xml +++ b/plugin.xml @@ -221,7 +221,9 @@ - + + + @@ -241,7 +243,9 @@ - + + + diff --git a/res/ios/en.lproj/DCLocalizable.strings b/res/ios/en.lproj/DCLocalizable.strings index 15df887a..825d3ebd 100644 --- a/res/ios/en.lproj/DCLocalizable.strings +++ b/res/ios/en.lproj/DCLocalizable.strings @@ -14,3 +14,12 @@ "fix-permission-action-button" = "Fix permission"; "precise-location-problem" = "The app does not have permission to read 'precise' location - background trip tracking will not work."; "notifications_blocked" = "Notifications blocked, please enable"; +"notifications_blocked_app_open" = "Notifications blocked, please fix in app settings"; +"location_not_enabled" = "Location turned off, please turn on"; +"location_permission_off" = "Insufficient location permissions, please fix"; +"location_permission_off_app_open" = "Insufficient location permissions, please fix in app settings"; +"location_permission_off_enable" = "Insufficient location permissions, please enable"; +"activity_permission_off" = "Motion and Fitness permission off, please enable"; +"activity_permission_off_app_open" = "Motion and Fitness permission off, please fix in app settings"; +"fix_app_status_title" = "Incorrect app settings"; +"fix_app_status_text" = "Click to view and fix app status"; diff --git a/src/ios/BEMDataCollection.m b/src/ios/BEMDataCollection.m index 3d325494..08f0828b 100644 --- a/src/ios/BEMDataCollection.m +++ b/src/ios/BEMDataCollection.m @@ -6,7 +6,7 @@ #import "DataUtils.h" #import "StatsEvent.h" #import "BEMBuiltinUserCache.h" -#import "TripDiarySettingsCheck.h" +#import "SensorControlForegroundDelegate.h" #import @implementation BEMDataCollection @@ -65,7 +65,9 @@ - (void)markConsented:(CDVInvokedUrlCommand*)command // which is actually easier ("always allow") // so in that case, we continue calling the init code in TripDiaryStateMachine [self initWithConsent]; + /* [TripDiarySettingsCheck checkMotionSettingsAndPermission:FALSE]; + */ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; [self.commandDelegate sendPluginResult:result callbackId:callbackId]; @@ -85,6 +87,8 @@ - (void)fixLocationSettings:(CDVInvokedUrlCommand*)command - (void)isValidLocationSettings:(CDVInvokedUrlCommand*)command { + [SensorControlForegroundDelegate checkLocationSettings:self.commandDelegate + forCommand:command]; } - (void)fixLocationPermissions:(CDVInvokedUrlCommand*)command @@ -93,6 +97,9 @@ - (void)fixLocationPermissions:(CDVInvokedUrlCommand*)command - (void)isValidLocationPermissions:(CDVInvokedUrlCommand*)command { + [SensorControlForegroundDelegate checkLocationPermissions:self.commandDelegate + forCommand:command]; + } - (void)fixFitnessPermissions:(CDVInvokedUrlCommand*)command @@ -101,16 +108,14 @@ - (void)fixFitnessPermissions:(CDVInvokedUrlCommand*)command - (void)isValidFitnessPermissions:(CDVInvokedUrlCommand*)command { -} + [SensorControlForegroundDelegate checkMotionActivityPermissions:self.commandDelegate + forCommand:command]; -- (UIUserNotificationSettings*) REQUESTED_NOTIFICATION_TYPES { - return [UIUserNotificationSettings - settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge - categories:nil]; } - (void)fixShowNotifications:(CDVInvokedUrlCommand*)command { + /* NSString* callbackId = [command callbackId]; @try { if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) { @@ -139,34 +144,14 @@ - (void)fixShowNotifications:(CDVInvokedUrlCommand*)command messageAsString:msg]; [self.commandDelegate sendPluginResult:result callbackId:callbackId]; } + */ } - (void)isValidShowNotifications:(CDVInvokedUrlCommand*)command { - NSString* callbackId = [command callbackId]; - @try { - UIUserNotificationSettings* requestedSettings = [self REQUESTED_NOTIFICATION_TYPES]; - UIUserNotificationSettings* currSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; - if (requestedSettings.types == currSettings.types) { - CDVPluginResult* result = [CDVPluginResult - resultWithStatus:CDVCommandStatus_OK]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } else { - NSString* msg = NSLocalizedStringFromTable(@"notifications_blocked", @"DCLocalizable", nil); - CDVPluginResult* result = [CDVPluginResult - resultWithStatus:CDVCommandStatus_ERROR - messageAsString:msg]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } - } - @catch (NSException *exception) { - NSString* msg = [NSString stringWithFormat: @"While getting settings, error %@", exception]; - CDVPluginResult* result = [CDVPluginResult - resultWithStatus:CDVCommandStatus_ERROR - messageAsString:msg]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - } + [SensorControlForegroundDelegate checkNotificationsEnabled:self.commandDelegate + forCommand:command]; } - (void)isNotificationsUnpaused:(CDVInvokedUrlCommand*)command diff --git a/src/ios/BEMRemotePushNotificationHandler.h b/src/ios/BEMRemotePushNotificationHandler.h index 8cf45b49..4163f3c7 100644 --- a/src/ios/BEMRemotePushNotificationHandler.h +++ b/src/ios/BEMRemotePushNotificationHandler.h @@ -3,7 +3,6 @@ @interface BEMRemotePushNotificationHandler : NSObject + (BEMRemotePushNotificationHandler*) instance; + (void) performPeriodicActivity; -+ (void) validateAndCleanupState; - (void) handleNotifications:(NSNotification*)note; @property NSMutableArray* silentPushHandlerList; diff --git a/src/ios/BEMRemotePushNotificationHandler.m b/src/ios/BEMRemotePushNotificationHandler.m index bc81b772..ae2ad9f1 100644 --- a/src/ios/BEMRemotePushNotificationHandler.m +++ b/src/ios/BEMRemotePushNotificationHandler.m @@ -1,6 +1,6 @@ #import "BEMRemotePushNotificationHandler.h" #import "TripDiaryStateMachine.h" -#import "TripDiarySettingsCheck.h" +#import "SensorControlBackgroundChecker.h" #import "LocalNotificationManager.h" @implementation BEMRemotePushNotificationHandler @@ -100,22 +100,8 @@ - (void)handleNotifications:(NSNotification*)note { + (void) performPeriodicActivity { - [TripDiarySettingsCheck checkSettingsAndPermission]; - [BEMRemotePushNotificationHandler validateAndCleanupState]; -} - -+ (void) validateAndCleanupState -{ - NSUInteger currState = [TripDiaryStateMachine instance].currState; - if (currState == kStartState) { - [LocalNotificationManager addNotification:[NSString stringWithFormat: - @"Still in start state, sending initialize..."] showUI:TRUE]; - [[NSNotificationCenter defaultCenter] postNotificationName:CFCTransitionNotificationName - object:CFCTransitionInitialize]; - } else { - [LocalNotificationManager addNotification:[NSString stringWithFormat: - @"In valid state %@, nothing to do...", [TripDiaryStateMachine getStateName:currState]] showUI:FALSE]; - } + [SensorControlBackgroundChecker checkAppState]; + [SensorControlBackgroundChecker restartFSMIfStartState]; } @end diff --git a/src/ios/Location/TripDiaryDelegate.m b/src/ios/Location/TripDiaryDelegate.m index ca4c58fd..a9ffb835 100644 --- a/src/ios/Location/TripDiaryDelegate.m +++ b/src/ios/Location/TripDiaryDelegate.m @@ -15,7 +15,7 @@ #import "LocationTrackingConfig.h" #import "ConfigManager.h" #import "BEMAppDelegate.h" -#import "TripDiarySettingsCheck.h" +#import "SensorControlBackgroundChecker.h" #define ACCURACY_THRESHOLD 200 @@ -228,9 +228,11 @@ - (void)locationManager:(CLLocationManager *)manager // and the background call to checkLocationSettingsAndPermission from the remote push code // doesn't have that reference. Can simplify this after we stop supporting iOS13. if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { - [TripDiarySettingsCheck promptForPermission:manager]; + // STATUS SCREEN: handle with checkAndFix + // [TripDiarySettingsCheck promptForPermission:manager]; } else { - [TripDiarySettingsCheck checkLocationSettingsAndPermission:FALSE]; + // STATUS SCREEN: handle with checkAndFix + // [TripDiarySettingsCheck checkLocationSettingsAndPermission:FALSE]; } if (_tdsm.currState == kStartState) { diff --git a/src/ios/Location/TripDiaryStateMachine.m b/src/ios/Location/TripDiaryStateMachine.m index 5d84b75d..83ceb564 100644 --- a/src/ios/Location/TripDiaryStateMachine.m +++ b/src/ios/Location/TripDiaryStateMachine.m @@ -9,7 +9,7 @@ #import "TripDiaryStateMachine.h" #import "TripDiaryActions.h" #import "TripDiaryDelegate.h" -#import "TripDiarySettingsCheck.h" +#import "SensorControlBackgroundChecker.h" #import "LocalNotificationManager.h" @@ -99,25 +99,38 @@ - (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: + 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]; } } + */ 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 @@ -203,6 +216,7 @@ -(void)setState:(TripDiaryStates) newState { [TripDiaryStateMachine getStateName:newState]]]; self.currState = newState; + [SensorControlBackgroundChecker checkAppState]; } /* @@ -248,7 +262,7 @@ -(void) handleStart:(NSString*) transition withUserInfo:(NSDictionary*) userInfo transition, [TripDiaryStateMachine getStateName:self.currState], [TripDiaryStateMachine getStateName:self.currState]); - [TripDiarySettingsCheck checkSettingsAndPermission]; + [SensorControlBackgroundChecker checkAppState]; } else if ([transition isEqualToString:CFCTransitionExitedGeofence]) { [TripDiaryActions startTracking:transition withLocationMgr:self.locMgr]; [TripDiaryActions deleteGeofence:self.locMgr]; @@ -397,8 +411,8 @@ - (void) handleOngoingTrip:(NSString*) transition withUserInfo:(NSDictionary*) u return nil; }]; } else if ([transition isEqualToString:CFCTransitionGeofenceCreationError]) { + // setState will call SensorControlBackgroundChecker checkAppState by default [self setState:kStartState]; - [TripDiarySettingsCheck checkSettingsAndPermission]; } else if ([transition isEqualToString:CFCTransitionForceStopTracking]) { [TripDiaryActions resetFSM:transition withLocationMgr:self.locMgr]; } else if ([transition isEqualToString:CFCTransitionTrackingStopped]) { diff --git a/src/ios/Verification/SensorControlBackgroundChecker.h b/src/ios/Verification/SensorControlBackgroundChecker.h new file mode 100644 index 00000000..7c565024 --- /dev/null +++ b/src/ios/Verification/SensorControlBackgroundChecker.h @@ -0,0 +1,11 @@ +#import +#import +#import +#import + +@interface SensorControlBackgroundChecker: NSObject + ++(void)restartFSMIfStartState; ++(void)checkAppState; + +@end diff --git a/src/ios/Verification/SensorControlBackgroundChecker.m b/src/ios/Verification/SensorControlBackgroundChecker.m new file mode 100644 index 00000000..2940bd93 --- /dev/null +++ b/src/ios/Verification/SensorControlBackgroundChecker.m @@ -0,0 +1,90 @@ +#import "SensorControlBackgroundChecker.h" +#import "TripDiarySensorControlChecks.h" +#import "TripDiaryStateMachine.h" +#import "LocalNotificationManager.h" +#import "BEMAppDelegate.h" +#import "BEMActivitySync.h" + +#import +#define OPEN_APP_STATUS_PAGE_ID @362253744 + +@implementation SensorControlBackgroundChecker + ++(NSDictionary*)OPEN_APP_STATUS_PAGE +{ + NSDictionary* config = @{ + @"id": OPEN_APP_STATUS_PAGE_ID, + @"title": NSLocalizedStringFromTable(@"fix_app_status_title", @"DCLocalizable", nil), + @"text": NSLocalizedStringFromTable(@"fix_app_status_text", @"DCLocalizable", nil), + @"data": @{ + @"redirectTo": @"root.main.control", + @"redirectParams": @{ + @"launchAppStatusModal": @true + } + } + }; + return config; +} + ++(void)restartFSMIfStartState +{ + NSUInteger currState = [TripDiaryStateMachine instance].currState; + if (currState == kStartState) { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"Still in start state, sending initialize..."] showUI:TRUE]; + [[NSNotificationCenter defaultCenter] postNotificationName:CFCTransitionNotificationName + object:CFCTransitionInitialize]; + } else { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"In valid state %@, nothing to do...", [TripDiaryStateMachine getStateName:currState]] showUI:FALSE]; + } +} + ++(void)checkAppState +{ + [LocalNotificationManager cancelNotification:OPEN_APP_STATUS_PAGE_ID]; + + NSArray* allChecks = @[ + @([TripDiarySensorControlChecks checkLocationSettings]), + @([TripDiarySensorControlChecks checkLocationPermissions]), + @([TripDiarySensorControlChecks checkMotionActivitySettings]), + @([TripDiarySensorControlChecks checkMotionActivityPermissions]), + @([TripDiarySensorControlChecks checkNotificationsEnabled]) + ]; + BOOL allChecksPass = true; + for (id check in allChecks) { + allChecksPass = allChecksPass && check; + } + + BOOL locChecksPass = allChecks[0] && allChecks[1]; + + if (allChecksPass) { + [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]; + } +} + ++(void)generateOpenAppSettingsNotification +{ + [LocalNotificationManager schedulePluginCompatibleNotification:[self OPEN_APP_STATUS_PAGE] withNewData:NULL]; +} +@end diff --git a/src/ios/Verification/SensorControlForegroundDelegate.h b/src/ios/Verification/SensorControlForegroundDelegate.h new file mode 100644 index 00000000..6c59573c --- /dev/null +++ b/src/ios/Verification/SensorControlForegroundDelegate.h @@ -0,0 +1,15 @@ +#import +#import +#import +#import +#import + +@interface SensorControlForegroundDelegate: NSObject + ++(void)checkLocationSettings:(id)delegate forCommand:(CDVInvokedUrlCommand*)command; ++(void)checkLocationPermissions:(id)delegate forCommand:(CDVInvokedUrlCommand*)command; ++(void)checkMotionActivitySettings:(id)delegate +forCommand:(CDVInvokedUrlCommand*)command; ++(void)checkMotionActivityPermissions:(id)delegate forCommand:(CDVInvokedUrlCommand*)command; ++(void)checkNotificationsEnabled:(id)delegate forCommand:(CDVInvokedUrlCommand*)command; +@end diff --git a/src/ios/Verification/SensorControlForegroundDelegate.m b/src/ios/Verification/SensorControlForegroundDelegate.m new file mode 100644 index 00000000..47c5c01c --- /dev/null +++ b/src/ios/Verification/SensorControlForegroundDelegate.m @@ -0,0 +1,82 @@ +#import "SensorControlForegroundDelegate.h" +#import "TripDiarySensorControlChecks.h" +#import "LocalNotificationManager.h" +#import "BEMAppDelegate.h" +#import "BEMActivitySync.h" + +#import + +@implementation SensorControlForegroundDelegate +// typedef BOOL (*CheckFnType)(void); + ++(void) sendCheckResult:(BOOL)result + forDelegate:(id) commandDelegate + forCommand:(CDVInvokedUrlCommand*)command + errorKey:(NSString*)localizableErrorKey +{ + NSString* callbackId = [command callbackId]; + @try { + if (result) { + CDVPluginResult* result = [CDVPluginResult + resultWithStatus:CDVCommandStatus_OK]; + [commandDelegate sendPluginResult:result callbackId:callbackId]; + } else { + NSString* msg = NSLocalizedStringFromTable(localizableErrorKey, @"DCLocalizable", nil); + CDVPluginResult* result = [CDVPluginResult + resultWithStatus:CDVCommandStatus_ERROR + messageAsString:msg]; + [commandDelegate sendPluginResult:result callbackId:callbackId]; + } + } + @catch (NSException *exception) { + NSString* msg = [NSString stringWithFormat: @"While getting settings, error %@", exception]; + CDVPluginResult* result = [CDVPluginResult + resultWithStatus:CDVCommandStatus_ERROR + messageAsString:msg]; + [commandDelegate sendPluginResult:result callbackId:callbackId]; + } +} + ++(void)checkLocationSettings:(id)delegate forCommand:(CDVInvokedUrlCommand*)command +{ + BOOL result = [TripDiarySensorControlChecks checkLocationSettings]; + [self sendCheckResult:result + forDelegate:delegate forCommand:command + errorKey:@"location_not_enabled"]; +} + ++(void)checkLocationPermissions:(id)delegate forCommand:(CDVInvokedUrlCommand*)command +{ + BOOL result = [TripDiarySensorControlChecks checkLocationPermissions]; + [self sendCheckResult:result + forDelegate:delegate forCommand:command + errorKey:@"location_permission_off"]; +} + ++(void)checkMotionActivitySettings:(id)delegate forCommand:(CDVInvokedUrlCommand*)command +{ + BOOL result = [TripDiarySensorControlChecks checkMotionActivitySettings]; + [self sendCheckResult:result + forDelegate:delegate forCommand:command + errorKey:@"activity_settings_off"]; +} + + ++(void)checkMotionActivityPermissions:(id)delegate forCommand:(CDVInvokedUrlCommand*)command +{ + BOOL result = [TripDiarySensorControlChecks checkMotionActivityPermissions]; + [self sendCheckResult:result + forDelegate:delegate forCommand:command + errorKey:@"activity_permission_off"]; +} + ++(void)checkNotificationsEnabled:(id)delegate forCommand:(CDVInvokedUrlCommand*)command +{ + BOOL result = [TripDiarySensorControlChecks checkNotificationsEnabled]; + [self sendCheckResult:result + forDelegate:delegate forCommand:command + errorKey:@"notifications_blocked"]; +} + + +@end diff --git a/src/ios/Verification/TripDiarySensorControlChecks.h b/src/ios/Verification/TripDiarySensorControlChecks.h index df0f7103..e951dea9 100644 --- a/src/ios/Verification/TripDiarySensorControlChecks.h +++ b/src/ios/Verification/TripDiarySensorControlChecks.h @@ -3,7 +3,13 @@ #import #import -@interface TripDiarySettingsCheck: NSObject +@interface TripDiarySensorControlChecks: NSObject + ++(BOOL)checkLocationSettings; ++(BOOL)checkLocationPermissions; ++(BOOL)checkMotionActivitySettings; ++(BOOL)checkMotionActivityPermissions; ++(BOOL)checkNotificationsEnabled; +(void)checkSettingsAndPermission; +(void)checkLocationSettingsAndPermission:(BOOL)inBackground; diff --git a/src/ios/Verification/TripDiarySensorControlChecks.m b/src/ios/Verification/TripDiarySensorControlChecks.m index b367dc71..522de697 100644 --- a/src/ios/Verification/TripDiarySensorControlChecks.m +++ b/src/ios/Verification/TripDiarySensorControlChecks.m @@ -1,12 +1,54 @@ -#import "TripDiarySettingsCheck.h" +#import "TripDiarySensorControlChecks.h" #import "LocalNotificationManager.h" #import "BEMAppDelegate.h" #import "BEMActivitySync.h" #import -@implementation TripDiarySettingsCheck +@implementation TripDiarySensorControlChecks ++(BOOL)checkLocationSettings { + return [CLLocationManager locationServicesEnabled]; +} + +// TODO: Decide whether we want to have a separate check for precise + ++(BOOL)checkLocationPermissions { + BOOL alwaysPerm = [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways; + BOOL precisePerm = TRUE; + CLLocationManager* currLocMgr = [TripDiaryStateMachine instance].locMgr; + if (@available(iOS 14.0, *)) { + CLAccuracyAuthorization preciseOrNot = [currLocMgr accuracyAuthorization]; + precisePerm = preciseOrNot == CLAccuracyAuthorizationFullAccuracy; + } else { + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"No precise location check needed for iOS < 14"]]; + } + [LocalNotificationManager addNotification:[NSString stringWithFormat:@"Returning combination of always = %@ and precise %@", @(alwaysPerm), @(precisePerm)]]; + return alwaysPerm && precisePerm; +} + ++(BOOL)checkMotionActivitySettings { + return [CMMotionActivityManager isActivityAvailable] == YES; +} + ++(BOOL)checkMotionActivityPermissions { + CMAuthorizationStatus currAuthStatus = [CMMotionActivityManager authorizationStatus]; + return currAuthStatus == CMAuthorizationStatusAuthorized; +} + ++(BOOL)checkNotificationsEnabled { + UIUserNotificationSettings* requestedSettings = [self REQUESTED_NOTIFICATION_TYPES]; + UIUserNotificationSettings* currSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + return requestedSettings.types == currSettings.types; +} + ++(UIUserNotificationSettings*) REQUESTED_NOTIFICATION_TYPES { + return [UIUserNotificationSettings + settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge + categories:nil]; +} + +/* +(void)checkSettingsAndPermission { [TripDiarySettingsCheck checkLocationSettingsAndPermission:TRUE]; [TripDiarySettingsCheck checkMotionSettingsAndPermission:TRUE]; @@ -139,5 +181,6 @@ +(void) showSettingsAlert:(UIAlertController*)alert { CDVViewController *vc = ad.viewController; [vc presentViewController:alert animated:YES completion:nil]; } +*/ @end