diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | chrome/browser/geolocation/core_location_data_provider_mac.h | 53 | ||||
-rw-r--r-- | chrome/browser/geolocation/core_location_data_provider_mac.mm | 241 | ||||
-rw-r--r-- | chrome/browser/geolocation/core_location_provider_mac.h | 36 | ||||
-rw-r--r-- | chrome/browser/geolocation/core_location_provider_mac.mm | 51 | ||||
-rw-r--r-- | chrome/browser/geolocation/gps_location_provider_linux.h | 2 | ||||
-rw-r--r-- | chrome/browser/geolocation/location_provider.cc | 2 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 |
10 files changed, 392 insertions, 2 deletions
@@ -84,3 +84,4 @@ litl LLC James Willcox <jwillcox@litl.com> Shreyas VA <v.a.shreyas@gmail.com> Steven Pennington <spenn@engr.uvic.ca> +Jorge Villatoro <jorge@tomatocannon.com> diff --git a/chrome/browser/geolocation/core_location_data_provider_mac.h b/chrome/browser/geolocation/core_location_data_provider_mac.h new file mode 100644 index 0000000..8eafd3c --- /dev/null +++ b/chrome/browser/geolocation/core_location_data_provider_mac.h @@ -0,0 +1,53 @@ +// Copyright (c) 2010 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 CHROME_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_ +#define CHROME_BROWSER_GEOLOCATION_CORE_LOCATION_DATA_PROVIDER_H_ +#pragma once + +#include "base/ref_counted.h" +#include "base/scoped_nsobject.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/geoposition.h" + +#import <Foundation/Foundation.h> + +class CoreLocationProviderMac; +@class CoreLocationWrapperMac; + +// 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); + + protected: + friend class base::RefCountedThreadSafe<CoreLocationDataProviderMac>; + ~CoreLocationDataProviderMac(); + + private: + // These must execute in ChromeThread::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 + scoped_nsobject<CoreLocationWrapperMac> wrapper_; + // The LocationProviderBase class that should receive position data + CoreLocationProviderMac* provider_; + ChromeThread::ID origin_thread_id_; +}; + +#endif diff --git a/chrome/browser/geolocation/core_location_data_provider_mac.mm b/chrome/browser/geolocation/core_location_data_provider_mac.mm new file mode 100644 index 0000000..ae8e749 --- /dev/null +++ b/chrome/browser/geolocation/core_location_data_provider_mac.mm @@ -0,0 +1,241 @@ +// Copyright (c) 2010 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 "chrome/browser/geolocation/core_location_data_provider_mac.h" +#include "chrome/browser/geolocation/core_location_provider_mac.h" +#include "base/logging.h" +#include "base/time.h" + +// 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 it's first +// successful call (to avoid |bundle_| being double initialized) +- (BOOL)locationDataAvailable; + +// These should always be called from ChromeThread::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_ 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 + +CoreLocationDataProviderMac::CoreLocationDataProviderMac() { + if(!ChromeThread::GetCurrentThreadIdentifier(&origin_thread_id_)) + NOTREACHED() << + "CoreLocation data provider must be created in a valid ChromeThread."; + 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; + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &CoreLocationDataProviderMac::StartUpdatingTask)); + return true; +} + +// Clears provider_ so that any leftover messages from CoreLocation get ignored +void CoreLocationDataProviderMac::StopUpdating() { + provider_ = NULL; + ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, + &CoreLocationDataProviderMac::StopUpdatingTask)); +} + +void CoreLocationDataProviderMac::UpdatePosition(Geoposition *position) { + ChromeThread::PostTask(origin_thread_id_, FROM_HERE, + NewRunnableMethod(this, + &CoreLocationDataProviderMac::PositionUpdated, + *position)); +} + +// Runs in ChromeThread::UI +void CoreLocationDataProviderMac::StartUpdatingTask() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + [wrapper_ startLocation]; +} + +// Runs in ChromeThread::UI +void CoreLocationDataProviderMac::StopUpdatingTask() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + [wrapper_ stopLocation]; +} + +void CoreLocationDataProviderMac::PositionUpdated(Geoposition position) { + DCHECK(ChromeThread::CurrentlyOn(origin_thread_id_)); + if(provider_) + provider_->SetPosition(&position); +} diff --git a/chrome/browser/geolocation/core_location_provider_mac.h b/chrome/browser/geolocation/core_location_provider_mac.h new file mode 100644 index 0000000..0d7d7470 --- /dev/null +++ b/chrome/browser/geolocation/core_location_provider_mac.h @@ -0,0 +1,36 @@ +// Copyright (c) 2010 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 CHROME_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_ +#define CHROME_BROWSER_GEOLOCATION_CORE_LOCATION_PROVIDER_MAC_H_ +#pragma once + +#include "chrome/browser/geolocation/location_provider.h" +#include "chrome/common/geoposition.h" + +class CoreLocationDataProviderMac; + +class CoreLocationProviderMac : public LocationProviderBase { + public: + explicit CoreLocationProviderMac(); + ~CoreLocationProviderMac(); + + // LocationProvider + virtual bool StartProvider(bool high_accuracy); + virtual void StopProvider(); + virtual void GetPosition(Geoposition* position); + + // Receives new positions and calls UpdateListeners + void SetPosition(Geoposition* position); + + private: + CoreLocationDataProviderMac* data_provider_; + Geoposition position_; +}; + +#endif diff --git a/chrome/browser/geolocation/core_location_provider_mac.mm b/chrome/browser/geolocation/core_location_provider_mac.mm new file mode 100644 index 0000000..e410426 --- /dev/null +++ b/chrome/browser/geolocation/core_location_provider_mac.mm @@ -0,0 +1,51 @@ +// Copyright (c) 2010 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 "chrome/browser/geolocation/core_location_provider_mac.h" +#include "chrome/browser/geolocation/core_location_data_provider_mac.h" + +#include "base/logging.h" +#include "base/command_line.h" +#include "chrome/common/chrome_switches.h" + +CoreLocationProviderMac::CoreLocationProviderMac() { + data_provider_ = new CoreLocationDataProviderMac(); + data_provider_->AddRef(); +} + +CoreLocationProviderMac::~CoreLocationProviderMac() { + data_provider_->StopUpdating(); + data_provider_->Release(); +} + +bool CoreLocationProviderMac::StartProvider(bool high_accuracy) { + data_provider_->StartUpdating(this); + return true; +} + +void CoreLocationProviderMac::StopProvider() { + data_provider_->StopUpdating(); +} + +void CoreLocationProviderMac::GetPosition(Geoposition* position) { + DCHECK(position); + *position = position_; + DCHECK(position->IsInitialized()); +} + +void CoreLocationProviderMac::SetPosition(Geoposition* position) { + DCHECK(position); + position_ = *position; + DCHECK(position->IsInitialized()); + + UpdateListeners(); +} + +LocationProviderBase* NewSystemLocationProvider() { + if(CommandLine::ForCurrentProcess() + ->HasSwitch(switches::kEnableCoreLocation)) { + return new CoreLocationProviderMac; + } + return NULL; +} diff --git a/chrome/browser/geolocation/gps_location_provider_linux.h b/chrome/browser/geolocation/gps_location_provider_linux.h index 68fff23..a06ccbd2 100644 --- a/chrome/browser/geolocation/gps_location_provider_linux.h +++ b/chrome/browser/geolocation/gps_location_provider_linux.h @@ -27,7 +27,7 @@ class GpsLocationProviderLinux : public LocationProviderBase { public: typedef LibGps* (*LibGpsFactory)(); // |factory| will be used to create the gpsd client library wrapper. (Note - // NewGpsLocationProvider() will use the default factory). + // NewSystemLocationProvider() will use the default factory). explicit GpsLocationProviderLinux(LibGpsFactory libgps_factory); virtual ~GpsLocationProviderLinux(); diff --git a/chrome/browser/geolocation/location_provider.cc b/chrome/browser/geolocation/location_provider.cc index ecd066e..7a868d7 100644 --- a/chrome/browser/geolocation/location_provider.cc +++ b/chrome/browser/geolocation/location_provider.cc @@ -56,7 +56,7 @@ void LocationProviderBase::UpdateListeners() { } } -#if !defined(OS_LINUX) && !defined(OS_WIN) +#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_WIN) LocationProviderBase* NewSystemLocationProvider() { return NULL; } diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 3a6884c..b0640b2 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1540,6 +1540,10 @@ 'browser/gears_integration.h', 'browser/geolocation/access_token_store.cc', 'browser/geolocation/access_token_store.h', + 'browser/geolocation/core_location_data_provider_mac.h', + 'browser/geolocation/core_location_data_provider_mac.mm', + 'browser/geolocation/core_location_provider_mac.h', + 'browser/geolocation/core_location_provider_mac.mm', 'browser/geolocation/device_data_provider.h', 'browser/geolocation/empty_device_data_provider.cc', 'browser/geolocation/empty_device_data_provider.h', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 9d38d74..ba036a4 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -393,6 +393,9 @@ const char kEnableContentPrefetch[] = "enable-content-prefetch"; // Enables the cookie prompt. const char kEnableCookiePrompt[] = "enable-cookie-prompt"; +// Enable CoreLocation geoposition data provider +const char kEnableCoreLocation[] = "enable-core-location"; + // Enables device motion events. const char kEnableDeviceMotion[] = "enable-device-motion"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index bcaacfe..efc74ec 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -122,6 +122,7 @@ extern const char kEnableCloudPrint[]; extern const char kEnableConnectBackupJobs[]; extern const char kEnableContentPrefetch[]; extern const char kEnableCookiePrompt[]; +extern const char kEnableCoreLocation[]; extern const char kEnableDeviceMotion[]; extern const char kEnableDNSSECCerts[]; extern const char kEnableExperimentalExtensionApis[]; |