summaryrefslogtreecommitdiff
path: root/chromium/content/browser/geolocation
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/geolocation')
-rw-r--r--chromium/content/browser/geolocation/core_location_data_provider_mac.h54
-rw-r--r--chromium/content/browser/geolocation/core_location_data_provider_mac.mm256
-rw-r--r--chromium/content/browser/geolocation/core_location_provider_mac.h40
-rw-r--r--chromium/content/browser/geolocation/core_location_provider_mac.mm68
-rw-r--r--chromium/content/browser/geolocation/geolocation_provider_impl.h7
-rw-r--r--chromium/content/browser/geolocation/location_arbitrator_impl.cc2
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();