diff options
Diffstat (limited to 'chromium/content/browser/geolocation')
6 files changed, 424 insertions, 3 deletions
diff --git a/chromium/content/browser/geolocation/core_location_data_provider_mac.h b/chromium/content/browser/geolocation/core_location_data_provider_mac.h new file mode 100644 index 00000000000..29204aa0d8c --- /dev/null +++ b/chromium/content/browser/geolocation/core_location_data_provider_mac.h @@ -0,0 +1,54 @@ +// Copyright (c) 2012 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. + +// This file declares a CoreLocation data provider class that allows the +// CoreLocation framework to run on the UI thread, since the Geolocation API's +// providers all live on the IO thread + +#ifndef CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_ +#define CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_ + +#include "base/mac/scoped_nsobject.h" +#include "base/memory/ref_counted.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/geoposition.h" + +#import <Foundation/Foundation.h> + +@class CoreLocationWrapperMac; + +namespace content { +class CoreLocationProviderMac; + +// Data provider class that allows CoreLocation to run in Chrome's UI thread +// while existing on any of Chrome's threads (in this case the IO thread) +class CoreLocationDataProviderMac + : public base::RefCountedThreadSafe<CoreLocationDataProviderMac> { + public: + CoreLocationDataProviderMac(); + + bool StartUpdating(CoreLocationProviderMac* provider); + void StopUpdating(); + + void UpdatePosition(Geoposition* position); + + private: + friend class base::RefCountedThreadSafe<CoreLocationDataProviderMac>; + ~CoreLocationDataProviderMac(); + + // These must execute in BrowserThread::UI + void StartUpdatingTask(); + void StopUpdatingTask(); + // This must execute in the origin thread (IO thread) + void PositionUpdated(Geoposition position); + + // The wrapper class that supplies this class with position data + base::scoped_nsobject<CoreLocationWrapperMac> wrapper_; + // The LocationProvider class that should receive position data + CoreLocationProviderMac* provider_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_ diff --git a/chromium/content/browser/geolocation/core_location_data_provider_mac.mm b/chromium/content/browser/geolocation/core_location_data_provider_mac.mm new file mode 100644 index 00000000000..8b1cf82c28b --- /dev/null +++ b/chromium/content/browser/geolocation/core_location_data_provider_mac.mm @@ -0,0 +1,256 @@ +// Copyright (c) 2012 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. + +// This file contains the class definitions for the CoreLocation data provider +// class and the accompanying Objective C wrapper class. This data provider +// is used to allow the CoreLocation wrapper to run on the UI thread, since +// CLLocationManager's start and stop updating methods must be called from a +// thread with an active NSRunLoop. Currently only the UI thread appears to +// fill that requirement. + +#include "content/browser/geolocation/core_location_data_provider_mac.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/time/time.h" +#include "content/browser/geolocation/core_location_provider_mac.h" +#include "content/browser/geolocation/geolocation_provider_impl.h" + +using content::CoreLocationDataProviderMac; +using content::Geoposition; + +// A few required declarations since the CoreLocation headers are not available +// with the Mac OS X 10.5 SDK. +// TODO(jorgevillatoro): Remove these declarations when we build against 10.6 + +// This idea was borrowed from wifi_data_provider_corewlan_mac.mm +typedef double CLLocationDegrees; +typedef double CLLocationAccuracy; +typedef double CLLocationSpeed; +typedef double CLLocationDirection; +typedef double CLLocationDistance; +typedef struct { + CLLocationDegrees latitude; + CLLocationDegrees longitude; +} CLLocationCoordinate2D; + +enum { + kCLErrorLocationUnknown = 0, + kCLErrorDenied +}; + +@interface CLLocationManager : NSObject ++ (BOOL)locationServicesEnabled; +@property(assign) id delegate; +- (void)startUpdatingLocation; +- (void)stopUpdatingLocation; +@end + +@interface CLLocation : NSObject<NSCopying, NSCoding> +@property(readonly) CLLocationCoordinate2D coordinate; +@property(readonly) CLLocationDistance altitude; +@property(readonly) CLLocationAccuracy horizontalAccuracy; +@property(readonly) CLLocationAccuracy verticalAccuracy; +@property(readonly) CLLocationDirection course; +@property(readonly) CLLocationSpeed speed; +@end + +@protocol CLLocationManagerDelegate +- (void)locationManager:(CLLocationManager*)manager + didUpdateToLocation:(CLLocation*)newLocation + fromLocation:(CLLocation*)oldLocation; +- (void)locationManager:(CLLocationManager*)manager + didFailWithError:(NSError*)error; +@end + +// This wrapper class receives CLLocation objects from CoreLocation, converts +// them to Geoposition objects, and passes them on to the data provider class +// Note: This class has some specific threading requirements, inherited from +// CLLocationManager. The location manaager's start and stop updating +// methods must be called from a thread that has an active run loop (which +// seems to only be the UI thread) +@interface CoreLocationWrapperMac : NSObject<CLLocationManagerDelegate> +{ + @private + NSBundle* bundle_; + Class locationManagerClass_; + id locationManager_; + CoreLocationDataProviderMac* dataProvider_; +} + +- (id)initWithDataProvider:(CoreLocationDataProviderMac*)dataProvider; +- (void)dealloc; + +// Can be called from any thread since it does not require an NSRunLoop. However +// it is not threadsafe to receive concurrent calls until after a first +// successful call (to avoid |bundle_| being double initialized) +- (BOOL)locationDataAvailable; + +// These should always be called from BrowserThread::UI +- (void)startLocation; +- (void)stopLocation; + +// These should only be called by CLLocationManager +- (void)locationManager:(CLLocationManager*)manager + didUpdateToLocation:(CLLocation*)newLocation + fromLocation:(CLLocation*)oldLocation; +- (void)locationManager:(CLLocationManager*)manager + didFailWithError:(NSError*)error; +- (BOOL)loadCoreLocationBundle; + +@end + +@implementation CoreLocationWrapperMac + +- (id)initWithDataProvider:(CoreLocationDataProviderMac*)dataProvider { + DCHECK(dataProvider); + dataProvider_ = dataProvider; + self = [super init]; + return self; +} + +- (void)dealloc { + [locationManager_ setDelegate:nil]; + [locationManager_ release]; + [locationManagerClass_ release]; + [bundle_ release]; + [super dealloc]; +} + +// Load the bundle and check to see if location services are enabled +// but don't do anything else +- (BOOL)locationDataAvailable { + return ([self loadCoreLocationBundle] && + [locationManagerClass_ locationServicesEnabled]); +} + +- (void)startLocation { + if ([self locationDataAvailable]) { + if (!locationManager_) { + locationManager_ = [[locationManagerClass_ alloc] init]; + [locationManager_ setDelegate:self]; + } + [locationManager_ startUpdatingLocation]; + } +} + +- (void)stopLocation { + [locationManager_ stopUpdatingLocation]; +} + +- (void)locationManager:(CLLocationManager*)manager + didUpdateToLocation:(CLLocation*)newLocation + fromLocation:(CLLocation*)oldLocation { + Geoposition position; + position.latitude = [newLocation coordinate].latitude; + position.longitude = [newLocation coordinate].longitude; + position.altitude = [newLocation altitude]; + position.accuracy = [newLocation horizontalAccuracy]; + position.altitude_accuracy = [newLocation verticalAccuracy]; + position.speed = [newLocation speed]; + position.heading = [newLocation course]; + position.timestamp = base::Time::Now(); + position.error_code = Geoposition::ERROR_CODE_NONE; + dataProvider_->UpdatePosition(&position); +} + +- (void)locationManager:(CLLocationManager*)manager + didFailWithError:(NSError*)error { + Geoposition position; + switch ([error code]) { + case kCLErrorLocationUnknown: + position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; + break; + case kCLErrorDenied: + position.error_code = Geoposition::ERROR_CODE_PERMISSION_DENIED; + break; + default: + NOTREACHED() << "Unknown CoreLocation error: " << [error code]; + return; + } + dataProvider_->UpdatePosition(&position); +} + +- (BOOL)loadCoreLocationBundle { + if (!bundle_) { + bundle_ = [[NSBundle alloc] + initWithPath:@"/System/Library/Frameworks/CoreLocation.framework"]; + if (!bundle_) { + DLOG(WARNING) << "Couldn't load CoreLocation Framework"; + return NO; + } + + locationManagerClass_ = [bundle_ classNamed:@"CLLocationManager"]; + } + + return YES; +} + +@end + +namespace content { + +CoreLocationDataProviderMac::CoreLocationDataProviderMac() { + if (base::MessageLoop::current() != + GeolocationProviderImpl::GetInstance()->message_loop()) { + NOTREACHED() << "CoreLocation data provider must be created on " + "the Geolocation thread."; + } + provider_ = NULL; + wrapper_.reset([[CoreLocationWrapperMac alloc] initWithDataProvider:this]); +} + +CoreLocationDataProviderMac::~CoreLocationDataProviderMac() { +} + +// Returns true if the CoreLocation wrapper can load the framework and +// location services are enabled. The pointer argument will only be accessed +// in the origin thread. +bool CoreLocationDataProviderMac:: + StartUpdating(CoreLocationProviderMac* provider) { + DCHECK(provider); + DCHECK(!provider_) << "StartUpdating called twice"; + if (![wrapper_ locationDataAvailable]) return false; + provider_ = provider; + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&CoreLocationDataProviderMac::StartUpdatingTask, this)); + return true; +} + +// Clears provider_ so that any leftover messages from CoreLocation get ignored +void CoreLocationDataProviderMac::StopUpdating() { + provider_ = NULL; + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&CoreLocationDataProviderMac::StopUpdatingTask, this)); +} + +void CoreLocationDataProviderMac::UpdatePosition(Geoposition *position) { + GeolocationProviderImpl::GetInstance()->message_loop()->PostTask( + FROM_HERE, + base::Bind(&CoreLocationDataProviderMac::PositionUpdated, this, + *position)); +} + +// Runs in BrowserThread::UI +void CoreLocationDataProviderMac::StartUpdatingTask() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + [wrapper_ startLocation]; +} + +// Runs in BrowserThread::UI +void CoreLocationDataProviderMac::StopUpdatingTask() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + [wrapper_ stopLocation]; +} + +void CoreLocationDataProviderMac::PositionUpdated(Geoposition position) { + DCHECK(base::MessageLoop::current() == + GeolocationProviderImpl::GetInstance()->message_loop()); + if (provider_) + provider_->SetPosition(&position); +} + +} // namespace content diff --git a/chromium/content/browser/geolocation/core_location_provider_mac.h b/chromium/content/browser/geolocation/core_location_provider_mac.h new file mode 100644 index 00000000000..b4186d4ffb8 --- /dev/null +++ b/chromium/content/browser/geolocation/core_location_provider_mac.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 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. + +// This file declares a CoreLocation provider that runs on Mac OS X (10.6). +// Public for testing only - for normal usage this header should not be +// required, as location_provider.h declares the needed factory function. + +#ifndef CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_ +#define CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_ + +#include "content/browser/geolocation/location_provider_base.h" +#include "content/public/common/geoposition.h" + +namespace content { +class CoreLocationDataProviderMac; + +class CoreLocationProviderMac : public LocationProviderBase { + public: + explicit CoreLocationProviderMac(); + virtual ~CoreLocationProviderMac(); + + // LocationProvider + virtual bool StartProvider(bool high_accuracy) OVERRIDE; + virtual void StopProvider() OVERRIDE; + virtual void GetPosition(Geoposition* position) OVERRIDE; + virtual void OnPermissionGranted() OVERRIDE; + + // Receives new positions and calls UpdateListeners + void SetPosition(Geoposition* position); + + private: + bool is_updating_; + CoreLocationDataProviderMac* data_provider_; + Geoposition position_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_ diff --git a/chromium/content/browser/geolocation/core_location_provider_mac.mm b/chromium/content/browser/geolocation/core_location_provider_mac.mm new file mode 100644 index 00000000000..1c3aca1195c --- /dev/null +++ b/chromium/content/browser/geolocation/core_location_provider_mac.mm @@ -0,0 +1,68 @@ +// Copyright (c) 2012 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. + +#include "content/browser/geolocation/core_location_provider_mac.h" + +#include "base/command_line.h" +#include "base/logging.h" +#include "content/browser/geolocation/core_location_data_provider_mac.h" +#include "content/public/common/content_switches.h" + +namespace content { + +CoreLocationProviderMac::CoreLocationProviderMac() + : is_updating_(false) { + data_provider_ = new CoreLocationDataProviderMac(); + data_provider_->AddRef(); +} + +CoreLocationProviderMac::~CoreLocationProviderMac() { + data_provider_->StopUpdating(); + data_provider_->Release(); +} + +bool CoreLocationProviderMac::StartProvider(bool high_accuracy) { + // StartProvider maybe called multiple times. For example, to update the high + // accuracy hint. + // TODO(jknotten): Support high_accuracy hint in underlying data provider. + if (is_updating_) + return true; + + is_updating_ = data_provider_->StartUpdating(this); + return true; +} + +void CoreLocationProviderMac::StopProvider() { + data_provider_->StopUpdating(); + is_updating_ = false; +} + +void CoreLocationProviderMac::GetPosition(Geoposition* position) { + DCHECK(position); + *position = position_; + DCHECK(position->Validate() || + position->error_code != Geoposition::ERROR_CODE_NONE); +} + +void CoreLocationProviderMac::OnPermissionGranted() { +} + +void CoreLocationProviderMac::SetPosition(Geoposition* position) { + DCHECK(position); + position_ = *position; + DCHECK(position->Validate() || + position->error_code != Geoposition::ERROR_CODE_NONE); + + NotifyCallback(position_); +} + +LocationProvider* NewSystemLocationProvider() { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kExperimentalLocationFeatures)) { + return new CoreLocationProviderMac; + } + return NULL; +} + +} // namespace content diff --git a/chromium/content/browser/geolocation/geolocation_provider_impl.h b/chromium/content/browser/geolocation/geolocation_provider_impl.h index 68e83a87968..d4b5afb1074 100644 --- a/chromium/content/browser/geolocation/geolocation_provider_impl.h +++ b/chromium/content/browser/geolocation/geolocation_provider_impl.h @@ -25,8 +25,11 @@ class GeolocationProviderTest; // This is the main API to the geolocation subsystem. The application will hold // a single instance of this class and can register multiple clients to be // notified of location changes: -// * Callbacks are registered by AddLocationUpdateCallback() and will keep -// receiving updates until unregistered by RemoveLocationUpdateCallback(). +// * Observers are registered by AddLocationUpdateCallback() and will keep +// receiving updates +// until unregistered by RemoveLocationUpdateCallback(). +// * Callbacks are registered by RequestCallback() and will be called exactly +// once when the next update becomes available. // The application must instantiate the GeolocationProvider on the IO thread and // must communicate with it on the same thread. // The underlying location arbitrator will only be enabled whilst there is at diff --git a/chromium/content/browser/geolocation/location_arbitrator_impl.cc b/chromium/content/browser/geolocation/location_arbitrator_impl.cc index 4befee2f4f8..49c1c10b85e 100644 --- a/chromium/content/browser/geolocation/location_arbitrator_impl.cc +++ b/chromium/content/browser/geolocation/location_arbitrator_impl.cc @@ -160,7 +160,7 @@ LocationProvider* GeolocationArbitratorImpl::NewNetworkLocationProvider( } LocationProvider* GeolocationArbitratorImpl::NewSystemLocationProvider() { -#if defined(OS_WIN) || defined(OS_MACOSX) +#if defined(OS_WIN) return NULL; #else return content::NewSystemLocationProvider(); |