blob: cab3ea7f1d571affde0f366e4605a8143cc64663 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// 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/location_manager.h"
#import "base/ios/weak_nsobject.h"
#include "base/mac/scoped_nsobject.h"
#import "ios/chrome/browser/geolocation/CLLocation+OmniboxGeolocation.h"
#import "ios/chrome/browser/geolocation/location_manager+Testing.h"
#import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
#import "ios/public/provider/chrome/browser/geolocation_updater_provider.h"
namespace {
const CLLocationDistance kLocationDesiredAccuracy =
kCLLocationAccuracyHundredMeters;
// Number of seconds to wait before automatically stopping location updates.
const NSTimeInterval kLocationStopUpdateDelay = 5.0;
// A large value to disable automatic location updates in GeolocationUpdater.
const NSTimeInterval kLocationUpdateInterval = 365.0 * 24.0 * 60.0 * 60.0;
} // namespace
@interface LocationManager () {
base::scoped_nsprotocol<id<GeolocationUpdater>> _locationUpdater;
base::scoped_nsobject<CLLocation> _currentLocation;
base::WeakNSProtocol<id<LocationManagerDelegate>> _delegate;
base::scoped_nsobject<NSDate> _startTime;
}
// Handles GeolocationUpdater notification for an updated device location.
- (void)handleLocationUpdateNotification:(NSNotification*)notification;
// Handles GeolocationUpdater notification for ending device location updates.
- (void)handleLocationStopNotification:(NSNotification*)notification;
// Handles GeolocationUpdater notification for changing authorization.
- (void)handleAuthorizationChangeNotification:(NSNotification*)notification;
@end
@implementation LocationManager
- (id)init {
self = [super init];
if (self) {
ios::GeolocationUpdaterProvider* provider =
ios::GetChromeBrowserProvider()->GetGeolocationUpdaterProvider();
// |provider| may be null in tests.
if (provider) {
_locationUpdater.reset(provider->CreateGeolocationUpdater(false));
[_locationUpdater setDesiredAccuracy:kLocationDesiredAccuracy
distanceFilter:kLocationDesiredAccuracy / 2];
[_locationUpdater setStopUpdateDelay:kLocationStopUpdateDelay];
[_locationUpdater setUpdateInterval:kLocationUpdateInterval];
NSNotificationCenter* defaultCenter =
[NSNotificationCenter defaultCenter];
[defaultCenter addObserver:self
selector:@selector(handleLocationUpdateNotification:)
name:provider->GetUpdateNotificationName()
object:_locationUpdater];
[defaultCenter addObserver:self
selector:@selector(handleLocationStopNotification:)
name:provider->GetStopNotificationName()
object:_locationUpdater];
[defaultCenter
addObserver:self
selector:@selector(handleAuthorizationChangeNotification:)
name:provider->GetAuthorizationChangeNotificationName()
object:nil];
}
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (CLAuthorizationStatus)authorizationStatus {
return [CLLocationManager authorizationStatus];
}
- (CLLocation*)currentLocation {
if (!_currentLocation)
_currentLocation.reset([[_locationUpdater currentLocation] retain]);
return _currentLocation;
}
- (id<LocationManagerDelegate>)delegate {
return _delegate;
}
- (void)setDelegate:(id<LocationManagerDelegate>)delegate {
_delegate.reset(delegate);
}
- (BOOL)locationServicesEnabled {
return [CLLocationManager locationServicesEnabled];
}
- (void)startUpdatingLocation {
CLLocation* currentLocation = self.currentLocation;
if (!currentLocation || [currentLocation cr_shouldRefresh]) {
if (![_locationUpdater isEnabled])
_startTime.reset([[NSDate alloc] init]);
[_locationUpdater requestWhenInUseAuthorization];
[_locationUpdater setEnabled:YES];
}
}
- (void)stopUpdatingLocation {
[_locationUpdater setEnabled:NO];
}
#pragma mark - Private
- (void)handleLocationUpdateNotification:(NSNotification*)notification {
NSString* newLocationKey = ios::GetChromeBrowserProvider()
->GetGeolocationUpdaterProvider()
->GetUpdateNewLocationKey();
CLLocation* location = [[notification userInfo] objectForKey:newLocationKey];
if (location) {
_currentLocation.reset([location retain]);
if (_startTime) {
NSTimeInterval interval = -[_startTime timeIntervalSinceNow];
[_currentLocation cr_setAcquisitionInterval:interval];
}
}
}
- (void)handleLocationStopNotification:(NSNotification*)notification {
[_locationUpdater setEnabled:NO];
}
- (void)handleAuthorizationChangeNotification:(NSNotification*)notification {
[_delegate locationManagerDidChangeAuthorizationStatus:self];
}
#pragma mark - LocationManager+Testing
- (void)setGeolocationUpdater:(id<GeolocationUpdater>)geolocationUpdater {
_locationUpdater.reset([geolocationUpdater retain]);
}
@end