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