| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright (c) 2010 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 // This file contains the class definitions for the CoreLocation data provider |  | 
| 6 // class and the accompanying Objective C wrapper class. This data provider |  | 
| 7 // is used to allow the CoreLocation wrapper to run on the UI thread, since |  | 
| 8 // CLLocationManager's start and stop updating methods must be called from a |  | 
| 9 // thread with an active NSRunLoop.  Currently only the UI thread appears to |  | 
| 10 // fill that requirement. |  | 
| 11 |  | 
| 12 #include "content/browser/geolocation/core_location_data_provider_mac.h" |  | 
| 13 |  | 
| 14 #include "base/logging.h" |  | 
| 15 #include "base/time.h" |  | 
| 16 #include "content/browser/geolocation/core_location_provider_mac.h" |  | 
| 17 #include "content/browser/geolocation/geolocation_provider.h" |  | 
| 18 |  | 
| 19 // A few required declarations since the CoreLocation headers are not available |  | 
| 20 // with the Mac OS X 10.5 SDK. |  | 
| 21 // TODO(jorgevillatoro): Remove these declarations when we build against 10.6 |  | 
| 22 |  | 
| 23 // This idea was borrowed from wifi_data_provider_corewlan_mac.mm |  | 
| 24 typedef double CLLocationDegrees; |  | 
| 25 typedef double CLLocationAccuracy; |  | 
| 26 typedef double CLLocationSpeed; |  | 
| 27 typedef double CLLocationDirection; |  | 
| 28 typedef double CLLocationDistance; |  | 
| 29 typedef struct { |  | 
| 30   CLLocationDegrees latitude; |  | 
| 31   CLLocationDegrees longitude; |  | 
| 32 } CLLocationCoordinate2D; |  | 
| 33 |  | 
| 34 enum { |  | 
| 35   kCLErrorLocationUnknown  = 0, |  | 
| 36   kCLErrorDenied |  | 
| 37 }; |  | 
| 38 |  | 
| 39 @interface CLLocationManager : NSObject |  | 
| 40 + (BOOL)locationServicesEnabled; |  | 
| 41 @property(assign) id delegate; |  | 
| 42 - (void)startUpdatingLocation; |  | 
| 43 - (void)stopUpdatingLocation; |  | 
| 44 @end |  | 
| 45 |  | 
| 46 @interface CLLocation : NSObject<NSCopying, NSCoding> |  | 
| 47 @property(readonly) CLLocationCoordinate2D coordinate; |  | 
| 48 @property(readonly) CLLocationDistance altitude; |  | 
| 49 @property(readonly) CLLocationAccuracy horizontalAccuracy; |  | 
| 50 @property(readonly) CLLocationAccuracy verticalAccuracy; |  | 
| 51 @property(readonly) CLLocationDirection course; |  | 
| 52 @property(readonly) CLLocationSpeed speed; |  | 
| 53 @end |  | 
| 54 |  | 
| 55 @protocol CLLocationManagerDelegate |  | 
| 56 - (void)locationManager:(CLLocationManager*)manager |  | 
| 57     didUpdateToLocation:(CLLocation*)newLocation |  | 
| 58            fromLocation:(CLLocation*)oldLocation; |  | 
| 59 - (void)locationManager:(CLLocationManager*)manager |  | 
| 60        didFailWithError:(NSError*)error; |  | 
| 61 @end |  | 
| 62 |  | 
| 63 // This wrapper class receives CLLocation objects from CoreLocation, converts |  | 
| 64 // them to Geoposition objects, and passes them on to the data provider class |  | 
| 65 // Note: This class has some specific threading requirements, inherited from |  | 
| 66 //       CLLocationManager.  The location manaager's start and stop updating |  | 
| 67 //       methods must be called from a thread that has an active run loop (which |  | 
| 68 //       seems to only be the UI thread) |  | 
| 69 @interface CoreLocationWrapperMac : NSObject<CLLocationManagerDelegate> |  | 
| 70 { |  | 
| 71  @private |  | 
| 72   NSBundle* bundle_; |  | 
| 73   Class locationManagerClass_; |  | 
| 74   id locationManager_; |  | 
| 75   CoreLocationDataProviderMac* dataProvider_; |  | 
| 76 } |  | 
| 77 |  | 
| 78 - (id)initWithDataProvider:(CoreLocationDataProviderMac*)dataProvider; |  | 
| 79 - (void)dealloc; |  | 
| 80 |  | 
| 81 // Can be called from any thread since it does not require an NSRunLoop. However |  | 
| 82 // it is not threadsafe to receive concurrent calls until after it's first |  | 
| 83 // successful call (to avoid |bundle_| being double initialized) |  | 
| 84 - (BOOL)locationDataAvailable; |  | 
| 85 |  | 
| 86 // These should always be called from BrowserThread::UI |  | 
| 87 - (void)startLocation; |  | 
| 88 - (void)stopLocation; |  | 
| 89 |  | 
| 90 // These should only be called by CLLocationManager |  | 
| 91 - (void)locationManager:(CLLocationManager*)manager |  | 
| 92     didUpdateToLocation:(CLLocation*)newLocation |  | 
| 93            fromLocation:(CLLocation*)oldLocation; |  | 
| 94 - (void)locationManager:(CLLocationManager*)manager |  | 
| 95        didFailWithError:(NSError*)error; |  | 
| 96 - (BOOL)loadCoreLocationBundle; |  | 
| 97 |  | 
| 98 @end |  | 
| 99 |  | 
| 100 @implementation CoreLocationWrapperMac |  | 
| 101 |  | 
| 102 - (id)initWithDataProvider:(CoreLocationDataProviderMac*)dataProvider { |  | 
| 103   DCHECK(dataProvider); |  | 
| 104   dataProvider_ = dataProvider; |  | 
| 105   self = [super init]; |  | 
| 106   return self; |  | 
| 107 } |  | 
| 108 |  | 
| 109 - (void)dealloc { |  | 
| 110   [locationManager_ release]; |  | 
| 111   [locationManagerClass_ release]; |  | 
| 112   [bundle_ release]; |  | 
| 113   [super dealloc]; |  | 
| 114 } |  | 
| 115 |  | 
| 116 // Load the bundle and check to see if location services are enabled |  | 
| 117 // but don't do anything else |  | 
| 118 - (BOOL)locationDataAvailable { |  | 
| 119   return ([self loadCoreLocationBundle] && |  | 
| 120           [locationManagerClass_ locationServicesEnabled]); |  | 
| 121 } |  | 
| 122 |  | 
| 123 - (void)startLocation { |  | 
| 124   if ([self locationDataAvailable]) { |  | 
| 125     if (!locationManager_) { |  | 
| 126       locationManager_ = [[locationManagerClass_ alloc] init]; |  | 
| 127       [locationManager_ setDelegate:self]; |  | 
| 128     } |  | 
| 129     [locationManager_ startUpdatingLocation]; |  | 
| 130   } |  | 
| 131 } |  | 
| 132 |  | 
| 133 - (void)stopLocation { |  | 
| 134   [locationManager_ stopUpdatingLocation]; |  | 
| 135 } |  | 
| 136 |  | 
| 137 - (void)locationManager:(CLLocationManager*)manager |  | 
| 138     didUpdateToLocation:(CLLocation*)newLocation |  | 
| 139            fromLocation:(CLLocation*)oldLocation { |  | 
| 140   Geoposition position; |  | 
| 141   position.latitude  = [newLocation coordinate].latitude; |  | 
| 142   position.longitude = [newLocation coordinate].longitude; |  | 
| 143   position.altitude  = [newLocation altitude]; |  | 
| 144   position.accuracy  = [newLocation horizontalAccuracy]; |  | 
| 145   position.altitude_accuracy = [newLocation verticalAccuracy]; |  | 
| 146   position.speed = [newLocation speed]; |  | 
| 147   position.heading = [newLocation course]; |  | 
| 148   position.timestamp = base::Time::Now(); |  | 
| 149   position.error_code = Geoposition::ERROR_CODE_NONE; |  | 
| 150   dataProvider_->UpdatePosition(&position); |  | 
| 151 } |  | 
| 152 |  | 
| 153 - (void)locationManager:(CLLocationManager*)manager |  | 
| 154        didFailWithError:(NSError*)error { |  | 
| 155   Geoposition position; |  | 
| 156   switch ([error code]) { |  | 
| 157     case kCLErrorLocationUnknown: |  | 
| 158       position.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; |  | 
| 159       break; |  | 
| 160     case kCLErrorDenied: |  | 
| 161       position.error_code = Geoposition::ERROR_CODE_PERMISSION_DENIED; |  | 
| 162       break; |  | 
| 163     default: |  | 
| 164       NOTREACHED() << "Unknown CoreLocation error: " << [error code]; |  | 
| 165       return; |  | 
| 166   } |  | 
| 167   dataProvider_->UpdatePosition(&position); |  | 
| 168 } |  | 
| 169 |  | 
| 170 - (BOOL)loadCoreLocationBundle { |  | 
| 171   if (!bundle_) { |  | 
| 172     bundle_ = [[NSBundle alloc] |  | 
| 173         initWithPath:@"/System/Library/Frameworks/CoreLocation.framework"]; |  | 
| 174     if (!bundle_) { |  | 
| 175       DLOG(WARNING) << "Couldn't load CoreLocation Framework"; |  | 
| 176       return NO; |  | 
| 177     } |  | 
| 178 |  | 
| 179     locationManagerClass_ = [bundle_ classNamed:@"CLLocationManager"]; |  | 
| 180   } |  | 
| 181 |  | 
| 182   return YES; |  | 
| 183 } |  | 
| 184 |  | 
| 185 @end |  | 
| 186 |  | 
| 187 CoreLocationDataProviderMac::CoreLocationDataProviderMac() { |  | 
| 188   if (MessageLoop::current() != |  | 
| 189       GeolocationProvider::GetInstance()->message_loop()) { |  | 
| 190     NOTREACHED() << "CoreLocation data provider must be created on " |  | 
| 191         "the Geolocation thread."; |  | 
| 192   } |  | 
| 193   provider_ = NULL; |  | 
| 194   wrapper_.reset([[CoreLocationWrapperMac alloc] initWithDataProvider:this]); |  | 
| 195 } |  | 
| 196 |  | 
| 197 CoreLocationDataProviderMac::~CoreLocationDataProviderMac() { |  | 
| 198 } |  | 
| 199 |  | 
| 200 // Returns true if the CoreLocation wrapper can load the framework and |  | 
| 201 // location services are enabled.  The pointer argument will only be accessed |  | 
| 202 // in the origin thread. |  | 
| 203 bool CoreLocationDataProviderMac:: |  | 
| 204     StartUpdating(CoreLocationProviderMac* provider) { |  | 
| 205   DCHECK(provider); |  | 
| 206   DCHECK(!provider_) << "StartUpdating called twice"; |  | 
| 207   if (![wrapper_ locationDataAvailable]) return false; |  | 
| 208   provider_ = provider; |  | 
| 209   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |  | 
| 210      NewRunnableMethod(this, &CoreLocationDataProviderMac::StartUpdatingTask)); |  | 
| 211   return true; |  | 
| 212 } |  | 
| 213 |  | 
| 214 // Clears provider_ so that any leftover messages from CoreLocation get ignored |  | 
| 215 void CoreLocationDataProviderMac::StopUpdating() { |  | 
| 216   provider_ = NULL; |  | 
| 217   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |  | 
| 218               NewRunnableMethod(this, |  | 
| 219                                &CoreLocationDataProviderMac::StopUpdatingTask)); |  | 
| 220 } |  | 
| 221 |  | 
| 222 void CoreLocationDataProviderMac::UpdatePosition(Geoposition *position) { |  | 
| 223   GeolocationProvider::GetInstance()->message_loop()->PostTask(FROM_HERE, |  | 
| 224               NewRunnableMethod(this, |  | 
| 225                                &CoreLocationDataProviderMac::PositionUpdated, |  | 
| 226                                *position)); |  | 
| 227 } |  | 
| 228 |  | 
| 229 // Runs in BrowserThread::UI |  | 
| 230 void CoreLocationDataProviderMac::StartUpdatingTask() { |  | 
| 231   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  | 
| 232   [wrapper_ startLocation]; |  | 
| 233 } |  | 
| 234 |  | 
| 235 // Runs in BrowserThread::UI |  | 
| 236 void CoreLocationDataProviderMac::StopUpdatingTask() { |  | 
| 237   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |  | 
| 238   [wrapper_ stopLocation]; |  | 
| 239 } |  | 
| 240 |  | 
| 241 void CoreLocationDataProviderMac::PositionUpdated(Geoposition position) { |  | 
| 242   DCHECK(MessageLoop::current() == |  | 
| 243          GeolocationProvider::GetInstance()->message_loop()); |  | 
| 244   if (provider_) |  | 
| 245     provider_->SetPosition(&position); |  | 
| 246 } |  | 
| OLD | NEW | 
|---|