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. 4 5#import "ios/chrome/browser/geolocation/location_manager.h" 6 7#include "ios/chrome/app/tests_hook.h" 8#import "ios/chrome/browser/geolocation/CLLocation+OmniboxGeolocation.h" 9#import "ios/chrome/browser/geolocation/location_manager+Testing.h" 10#import "ios/public/provider/chrome/browser/chrome_browser_provider.h" 11#import "ios/public/provider/chrome/browser/geolocation_updater_provider.h" 12 13#if !defined(__has_feature) || !__has_feature(objc_arc) 14#error "This file requires ARC support." 15#endif 16 17namespace { 18 19const CLLocationDistance kLocationDesiredAccuracy = 20 kCLLocationAccuracyHundredMeters; 21// Number of seconds to wait before automatically stopping location updates. 22const NSTimeInterval kLocationStopUpdateDelay = 5.0; 23// A large value to disable automatic location updates in GeolocationUpdater. 24const NSTimeInterval kLocationUpdateInterval = 365.0 * 24.0 * 60.0 * 60.0; 25 26} // namespace 27 28@interface LocationManager () { 29 id<GeolocationUpdater> _locationUpdater; 30 NSDate* _startTime; 31} 32 33// Handles GeolocationUpdater notification for an updated device location. 34- (void)handleLocationUpdateNotification:(NSNotification*)notification; 35// Handles GeolocationUpdater notification for ending device location updates. 36- (void)handleLocationStopNotification:(NSNotification*)notification; 37// Handles GeolocationUpdater notification for changing authorization. 38- (void)handleAuthorizationChangeNotification:(NSNotification*)notification; 39 40@end 41 42@implementation LocationManager 43@synthesize delegate = _delegate; 44@synthesize currentLocation = _currentLocation; 45 46- (id)init { 47 self = [super init]; 48 if (self) { 49 ios::GeolocationUpdaterProvider* provider = 50 ios::GetChromeBrowserProvider()->GetGeolocationUpdaterProvider(); 51 52 // |provider| may be null in tests. 53 if (provider) { 54 _locationUpdater = provider->CreateGeolocationUpdater(false); 55 [_locationUpdater setDesiredAccuracy:kLocationDesiredAccuracy 56 distanceFilter:kLocationDesiredAccuracy / 2]; 57 [_locationUpdater setStopUpdateDelay:kLocationStopUpdateDelay]; 58 [_locationUpdater setUpdateInterval:kLocationUpdateInterval]; 59 60 NSNotificationCenter* defaultCenter = 61 [NSNotificationCenter defaultCenter]; 62 [defaultCenter addObserver:self 63 selector:@selector(handleLocationUpdateNotification:) 64 name:provider->GetUpdateNotificationName() 65 object:_locationUpdater]; 66 [defaultCenter addObserver:self 67 selector:@selector(handleLocationStopNotification:) 68 name:provider->GetStopNotificationName() 69 object:_locationUpdater]; 70 [defaultCenter 71 addObserver:self 72 selector:@selector(handleAuthorizationChangeNotification:) 73 name:provider->GetAuthorizationChangeNotificationName() 74 object:nil]; 75 } 76 } 77 return self; 78} 79 80- (CLAuthorizationStatus)authorizationStatus { 81 return [CLLocationManager authorizationStatus]; 82} 83 84- (CLLocation*)currentLocation { 85 if (!_currentLocation) 86 _currentLocation = [_locationUpdater currentLocation]; 87 return _currentLocation; 88} 89 90- (BOOL)locationServicesEnabled { 91 return !tests_hook::DisableGeolocation() && 92 [CLLocationManager locationServicesEnabled]; 93} 94 95- (void)startUpdatingLocation { 96 CLLocation* currentLocation = self.currentLocation; 97 if (!currentLocation || [currentLocation cr_shouldRefresh]) { 98 if (![_locationUpdater isEnabled]) 99 _startTime = [[NSDate alloc] init]; 100 101 [_locationUpdater requestWhenInUseAuthorization]; 102 [_locationUpdater setEnabled:YES]; 103 } 104} 105 106- (void)stopUpdatingLocation { 107 [_locationUpdater setEnabled:NO]; 108} 109 110#pragma mark - Private 111 112- (void)handleLocationUpdateNotification:(NSNotification*)notification { 113 NSString* newLocationKey = ios::GetChromeBrowserProvider() 114 ->GetGeolocationUpdaterProvider() 115 ->GetUpdateNewLocationKey(); 116 CLLocation* location = [[notification userInfo] objectForKey:newLocationKey]; 117 if (location) { 118 _currentLocation = location; 119 120 if (_startTime) { 121 NSTimeInterval interval = -[_startTime timeIntervalSinceNow]; 122 [_currentLocation cr_setAcquisitionInterval:interval]; 123 } 124 } 125} 126 127- (void)handleLocationStopNotification:(NSNotification*)notification { 128 [_locationUpdater setEnabled:NO]; 129} 130 131- (void)handleAuthorizationChangeNotification:(NSNotification*)notification { 132 [_delegate locationManagerDidChangeAuthorizationStatus:self]; 133} 134 135#pragma mark - LocationManager+Testing 136 137- (void)setGeolocationUpdater:(id<GeolocationUpdater>)geolocationUpdater { 138 _locationUpdater = geolocationUpdater; 139} 140 141@end 142