diff --git a/Source/INTULocationManager.h b/Source/INTULocationManager.h index bb61326..6081265 100644 --- a/Source/INTULocationManager.h +++ b/Source/INTULocationManager.h @@ -27,12 +27,12 @@ /** An abstraction around CLLocationManager that provides a block-based asynchronous API for obtaining the device's location. - This class will automatically start and stop system location services as needed to conserve battery. + INTULocationManager automatically starts and stops system location services as needed to minimize battery drain. */ @interface INTULocationManager : NSObject -/** Returns YES if location services are enabled in the system settings, and the app has NOT been denied/restricted access. Returns NO otherwise. */ -@property (nonatomic, readonly) BOOL locationServicesAvailable; +/** Returns the current state of location services for this app, based on the system settings and user authorization status. */ ++ (INTULocationServicesState)locationServicesState; /** Returns the singleton instance of this class. */ + (instancetype)sharedInstance; @@ -90,3 +90,15 @@ - (void)cancelLocationRequest:(INTULocationRequestID)requestID; @end + + +/** + A category on INTULocationManager that exposes deprecated legacy APIs. These should no longer be used, and will be removed in a future release. + */ +@interface INTULocationManager (Deprecated) + +/** DEPRECATED, will be removed in a future release. Please use +[INTULocationManager locationServicesState] instead. + Returns YES if location services are enabled in the system settings, and the app has NOT been denied/restricted access. Returns NO otherwise. */ +@property (nonatomic, readonly) BOOL locationServicesAvailable __attribute__((deprecated)); + +@end diff --git a/Source/INTULocationManager.m b/Source/INTULocationManager.m index 5e8a1f0..fcbf6cf 100644 --- a/Source/INTULocationManager.m +++ b/Source/INTULocationManager.m @@ -65,6 +65,30 @@ @implementation INTULocationManager static id _sharedInstance; +/** + Returns the current state of location services for this app, based on the system settings and user authorization status. + */ ++ (INTULocationServicesState)locationServicesState +{ + if ([CLLocationManager locationServicesEnabled] == NO) { + return INTULocationServicesStateDisabled; + } + else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { + return INTULocationServicesStateNotDetermined; + } + else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { + return INTULocationServicesStateDenied; + } + else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) { + return INTULocationServicesStateRestricted; + } + + return INTULocationServicesStateAvailable; +} + +/** + Returns the singleton instance of this class. + */ + (instancetype)sharedInstance { static dispatch_once_t _onceToken; @@ -86,22 +110,6 @@ - (instancetype)init return self; } -/** - Returns YES if location services are enabled in the system settings, and the app has NOT been denied/restricted access. Returns NO otherwise. - Note that this method will return YES even if the authorization status has not yet been determined. - */ -- (BOOL)locationServicesAvailable -{ - if ([CLLocationManager locationServicesEnabled] == NO) { - return NO; - } else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { - return NO; - } else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) { - return NO; - } - return YES; -} - /** Asynchronously requests the current location of the device using location services. @@ -239,8 +247,11 @@ - (void)cancelLocationRequest:(INTULocationRequestID)requestID */ - (void)addLocationRequest:(INTULocationRequest *)locationRequest { - if ([self locationServicesAvailable] == NO) { - // Don't even bother trying to do anything since location services are off or the user has explcitly denied us permission to use them + INTULocationServicesState locationServicesState = [INTULocationManager locationServicesState]; + if (locationServicesState == INTULocationServicesStateDisabled || + locationServicesState == INTULocationServicesStateDenied || + locationServicesState == INTULocationServicesStateRestricted) { + // No need to add this location request, because location services are turned off device-wide, or the user has denied this app permissions to use them [self completeLocationRequest:locationRequest]; return; } @@ -428,16 +439,18 @@ - (void)processSubscriptionRequest:(INTULocationRequest *)locationRequest */ - (INTULocationStatus)statusForLocationRequest:(INTULocationRequest *)locationRequest { - if ([CLLocationManager locationServicesEnabled] == NO) { + INTULocationServicesState locationServicesState = [INTULocationManager locationServicesState]; + + if (locationServicesState == INTULocationServicesStateDisabled) { return INTULocationStatusServicesDisabled; } - else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { + else if (locationServicesState == INTULocationServicesStateNotDetermined) { return INTULocationStatusServicesNotDetermined; } - else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { + else if (locationServicesState == INTULocationServicesStateDenied) { return INTULocationStatusServicesDenied; } - else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) { + else if (locationServicesState == INTULocationServicesStateRestricted) { return INTULocationStatusServicesRestricted; } else if (self.updateFailed) { @@ -546,5 +559,27 @@ - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatu } } } + +#pragma mark Deprecated methods + +/** + DEPRECATED, will be removed in a future release. Please use +[INTULocationManager locationServicesState] instead. + Returns YES if location services are enabled in the system settings, and the app has NOT been denied/restricted access. Returns NO otherwise. + Note that this method will return YES even if the authorization status has not yet been determined. + */ +- (BOOL)locationServicesAvailable +{ + if ([CLLocationManager locationServicesEnabled] == NO) { + return NO; + } + else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { + return NO; + } + else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) { + return NO; + } + + return YES; +} @end diff --git a/Source/INTULocationRequestDefines.h b/Source/INTULocationRequestDefines.h index 3f30595..211a70a 100644 --- a/Source/INTULocationRequestDefines.h +++ b/Source/INTULocationRequestDefines.h @@ -41,6 +41,21 @@ static const CGFloat kINTUUpdateTimeStaleThresholdBlock = 60.0; // static const CGFloat kINTUUpdateTimeStaleThresholdHouse = 15.0; // in seconds static const CGFloat kINTUUpdateTimeStaleThresholdRoom = 5.0; // in seconds +/** The possible states that location services can be in. */ +typedef NS_ENUM(NSInteger, INTULocationServicesState) { + /** User has already granted this app permissions to access location services, and they are enabled and ready for use by this app. + Note: this state will be returned for both the "When In Use" and "Always" permission levels. */ + INTULocationServicesStateAvailable, + /** User has not yet responded to the dialog that grants this app permission to access location services. */ + INTULocationServicesStateNotDetermined, + /** User has explicitly denied this app permission to access location services. (The user can enable permissions again for this app from the system Settings app.) */ + INTULocationServicesStateDenied, + /** User does not have ability to enable location services (e.g. parental controls, corporate policy, etc). */ + INTULocationServicesStateRestricted, + /** User has turned off location services device-wide (for all apps) from the system Settings app. */ + INTULocationServicesStateDisabled +}; + /** A unique ID that corresponds to one location request. */ typedef NSInteger INTULocationRequestID; @@ -64,7 +79,7 @@ typedef NS_ENUM(NSInteger, INTULocationAccuracy) { INTULocationAccuracyRoom, }; -/** Statuses that can be passed to the completion block of a location request. */ +/** A status that will be passed in to the completion block of a location request. */ typedef NS_ENUM(NSInteger, INTULocationStatus) { // These statuses will accompany a valid location. /** Got a location and desired accuracy level was achieved successfully. */ @@ -73,13 +88,13 @@ typedef NS_ENUM(NSInteger, INTULocationStatus) { INTULocationStatusTimedOut, // These statuses indicate some sort of error, and will accompany a nil location. - /** User has not responded to the permissions dialog. */ + /** User has not yet responded to the dialog that grants this app permission to access location services. */ INTULocationStatusServicesNotDetermined, /** User has explicitly denied this app permission to access location services. */ INTULocationStatusServicesDenied, /** User does not have ability to enable location services (e.g. parental controls, corporate policy, etc). */ INTULocationStatusServicesRestricted, - /** User has turned off device-wide location services from system settings. */ + /** User has turned off location services device-wide (for all apps) from the system Settings app. */ INTULocationStatusServicesDisabled, /** An error occurred while using the system location services. */ INTULocationStatusError