| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/geolocation/model/geolocation_manager.h" |
| |
| #import <CoreLocation/CoreLocation.h> |
| |
| #import <optional> |
| |
| #import "base/metrics/histogram_macros.h" |
| #import "ios/chrome/browser/geolocation/model/authorization_status_cache_util.h" |
| |
| namespace { |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| // |
| // LINT.IfChange(AuthorizationStatus) |
| enum class AuthorizationStatus { |
| // The user has not chosen whether to allow location access. |
| kNotDetermined = 0, |
| // The user cannot allow location access. |
| kRestricted = 1, |
| // The user denied location access either for the app or globally. |
| kDenied = 2, |
| // The user granted location access at all times. |
| kAuthorizedAlways = 3, |
| // The user granted location access only while the app is in use. |
| kAuthorizedWhenInUse = 4, |
| kMaxValue = kAuthorizedWhenInUse |
| }; |
| // LINT.ThenChange(/tools/metrics/histograms/metadata/geolocation/enums.xml) |
| |
| // Name of the histogram recording initial geolocation authorization state. |
| constexpr char kGeolocationInitialAuthorizationStateHistogram[] = |
| "Geolocation.IOS.InitialAuthorizationState"; |
| |
| // Name of the histogram recording a change in geolocation authorization state. |
| constexpr char kGeolocationAuthorizationStateChangedHistogram[] = |
| "Geolocation.IOS.ChangedAuthorizationState"; |
| |
| AuthorizationStatus ToAuthorizationStatus( |
| CLAuthorizationStatus authorization_status) { |
| switch (authorization_status) { |
| case kCLAuthorizationStatusNotDetermined: |
| return AuthorizationStatus::kNotDetermined; |
| case kCLAuthorizationStatusRestricted: |
| return AuthorizationStatus::kRestricted; |
| case kCLAuthorizationStatusDenied: |
| return AuthorizationStatus::kDenied; |
| case kCLAuthorizationStatusAuthorizedAlways: |
| return AuthorizationStatus::kAuthorizedAlways; |
| case kCLAuthorizationStatusAuthorizedWhenInUse: |
| return AuthorizationStatus::kAuthorizedWhenInUse; |
| default: |
| // Since CLAuthorizationStatus is an iOS-provided enum, safely handle new |
| // values by falling back to `kNotDetermined`. |
| return AuthorizationStatus::kNotDetermined; |
| } |
| } |
| |
| } // anonymous namespace |
| |
| @interface GeolocationManager () <CLLocationManagerDelegate> |
| |
| @property(nonatomic, strong) CLLocationManager* locationManager; |
| |
| // The status received during this application run |
| @property(nonatomic) std::optional<CLAuthorizationStatus> status; |
| |
| @end |
| |
| @implementation GeolocationManager |
| |
| + (GeolocationManager*)sharedInstance { |
| static GeolocationManager* instance = [[GeolocationManager alloc] init]; |
| return instance; |
| } |
| |
| + (GeolocationManager*)createForTesting { |
| return [[GeolocationManager alloc] init]; |
| } |
| |
| - (instancetype)init { |
| self = [super init]; |
| if (self) { |
| _locationManager = [[CLLocationManager alloc] init]; |
| [_locationManager setDelegate:self]; |
| } |
| return self; |
| } |
| |
| - (CLAuthorizationStatus)authorizationStatus { |
| if (self.status) { |
| return static_cast<CLAuthorizationStatus>(self.status.value()); |
| } |
| |
| std::optional<CLAuthorizationStatus> cached_status = |
| authorization_status_cache_util::GetAuthorizationStatus(); |
| if (cached_status) { |
| return cached_status.value(); |
| } |
| |
| return kCLAuthorizationStatusNotDetermined; |
| } |
| |
| #pragma mark - CLLocationManagerDelegate |
| |
| - (void)locationManagerDidChangeAuthorization: |
| (CLLocationManager*)locationManager { |
| self.status = self.locationManager.authorizationStatus; |
| |
| authorization_status_cache_util::SetAuthorizationStatus(self.status.value()); |
| |
| // The initial call to this method represents the initial value of geolocation |
| // authorization status rather than a change. |
| static BOOL initialCall = YES; |
| if (initialCall) { |
| initialCall = NO; |
| UMA_HISTOGRAM_ENUMERATION(kGeolocationInitialAuthorizationStateHistogram, |
| ToAuthorizationStatus(self.status.value())); |
| return; |
| } |
| |
| UMA_HISTOGRAM_ENUMERATION(kGeolocationAuthorizationStateChangedHistogram, |
| ToAuthorizationStatus(self.status.value())); |
| } |
| |
| @end |