1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/chrome/browser/geolocation/location_manager.h"
7 #import "base/ios/weak_nsobject.h"
8 #include "base/mac/scoped_nsobject.h"
9 #import "ios/chrome/browser/geolocation/CLLocation+OmniboxGeolocation.h"
10 #import "ios/chrome/browser/geolocation/location_manager+Testing.h"
11 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
12 #import "ios/public/provider/chrome/browser/geolocation_updater_provider.h"
16 const CLLocationDistance kLocationDesiredAccuracy =
17 kCLLocationAccuracyHundredMeters;
18 // Number of seconds to wait before automatically stopping location updates.
19 const NSTimeInterval kLocationStopUpdateDelay = 5.0;
20 // A large value to disable automatic location updates in GeolocationUpdater.
21 const NSTimeInterval kLocationUpdateInterval = 365.0 * 24.0 * 60.0 * 60.0;
25 @interface LocationManager () {
26 base::scoped_nsprotocol<id<GeolocationUpdater>> _locationUpdater;
27 base::scoped_nsobject<CLLocation> _currentLocation;
28 base::WeakNSProtocol<id<LocationManagerDelegate>> _delegate;
29 base::scoped_nsobject<NSDate> _startTime;
32 // Handles GeolocationUpdater notification for an updated device location.
33 - (void)handleLocationUpdateNotification:(NSNotification*)notification;
34 // Handles GeolocationUpdater notification for ending device location updates.
35 - (void)handleLocationStopNotification:(NSNotification*)notification;
36 // Handles GeolocationUpdater notification for changing authorization.
37 - (void)handleAuthorizationChangeNotification:(NSNotification*)notification;
41 @implementation LocationManager
46 ios::GeolocationUpdaterProvider* provider =
47 ios::GetChromeBrowserProvider()->GetGeolocationUpdaterProvider();
49 // |provider| may be null in tests.
51 _locationUpdater.reset(provider->CreateGeolocationUpdater(false));
52 [_locationUpdater setDesiredAccuracy:kLocationDesiredAccuracy
53 distanceFilter:kLocationDesiredAccuracy / 2];
54 [_locationUpdater setStopUpdateDelay:kLocationStopUpdateDelay];
55 [_locationUpdater setUpdateInterval:kLocationUpdateInterval];
57 NSNotificationCenter* defaultCenter =
58 [NSNotificationCenter defaultCenter];
59 [defaultCenter addObserver:self
60 selector:@selector(handleLocationUpdateNotification:)
61 name:provider->GetUpdateNotificationName()
62 object:_locationUpdater];
63 [defaultCenter addObserver:self
64 selector:@selector(handleLocationStopNotification:)
65 name:provider->GetStopNotificationName()
66 object:_locationUpdater];
69 selector:@selector(handleAuthorizationChangeNotification:)
70 name:provider->GetAuthorizationChangeNotificationName()
78 [[NSNotificationCenter defaultCenter] removeObserver:self];
82 - (CLAuthorizationStatus)authorizationStatus {
83 return [CLLocationManager authorizationStatus];
86 - (CLLocation*)currentLocation {
87 if (!_currentLocation)
88 _currentLocation.reset([[_locationUpdater currentLocation] retain]);
89 return _currentLocation;
92 - (id<LocationManagerDelegate>)delegate {
96 - (void)setDelegate:(id<LocationManagerDelegate>)delegate {
97 _delegate.reset(delegate);
100 - (BOOL)locationServicesEnabled {
101 return [CLLocationManager locationServicesEnabled];
104 - (void)startUpdatingLocation {
105 CLLocation* currentLocation = self.currentLocation;
106 if (!currentLocation || [currentLocation cr_shouldRefresh]) {
107 if (![_locationUpdater isEnabled])
108 _startTime.reset([[NSDate alloc] init]);
110 [_locationUpdater requestWhenInUseAuthorization];
111 [_locationUpdater setEnabled:YES];
115 - (void)stopUpdatingLocation {
116 [_locationUpdater setEnabled:NO];
119 #pragma mark - Private
121 - (void)handleLocationUpdateNotification:(NSNotification*)notification {
122 NSString* newLocationKey = ios::GetChromeBrowserProvider()
123 ->GetGeolocationUpdaterProvider()
124 ->GetUpdateNewLocationKey();
125 CLLocation* location = [[notification userInfo] objectForKey:newLocationKey];
127 _currentLocation.reset([location retain]);
130 NSTimeInterval interval = -[_startTime timeIntervalSinceNow];
131 [_currentLocation cr_setAcquisitionInterval:interval];
136 - (void)handleLocationStopNotification:(NSNotification*)notification {
137 [_locationUpdater setEnabled:NO];
140 - (void)handleAuthorizationChangeNotification:(NSNotification*)notification {
141 [_delegate locationManagerDidChangeAuthorizationStatus:self];
144 #pragma mark - LocationManager+Testing
146 - (void)setGeolocationUpdater:(id<GeolocationUpdater>)geolocationUpdater {
147 _locationUpdater.reset([geolocationUpdater retain]);