|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "nsCOMPtr.h" |
|
8 #include "nsGeoPosition.h" |
|
9 #include "nsIConsoleService.h" |
|
10 #include "nsServiceManagerUtils.h" |
|
11 #include "nsIDOMGeoPositionError.h" |
|
12 #include "CoreLocationLocationProvider.h" |
|
13 #include "nsCocoaFeatures.h" |
|
14 #include "prtime.h" |
|
15 |
|
16 #include <CoreLocation/CLError.h> |
|
17 #include <CoreLocation/CLLocation.h> |
|
18 #include <CoreLocation/CLLocationManager.h> |
|
19 #include <CoreLocation/CLLocationManagerDelegate.h> |
|
20 |
|
21 #include <objc/objc.h> |
|
22 #include <objc/objc-runtime.h> |
|
23 |
|
24 #include "nsObjCExceptions.h" |
|
25 |
|
26 using namespace mozilla; |
|
27 |
|
28 static const CLLocationAccuracy kHIGH_ACCURACY = kCLLocationAccuracyBest; |
|
29 static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTenMeters; |
|
30 |
|
31 @interface LocationDelegate : NSObject <CLLocationManagerDelegate> |
|
32 { |
|
33 CoreLocationLocationProvider* mProvider; |
|
34 } |
|
35 |
|
36 - (id)init:(CoreLocationLocationProvider*)aProvider; |
|
37 - (void)locationManager:(CLLocationManager*)aManager |
|
38 didFailWithError:(NSError *)aError; |
|
39 |
|
40 /* XXX (ggp) didUpdateToLocation is supposedly deprecated in favor of |
|
41 * locationManager:didUpdateLocations, which is undocumented and didn't seem to |
|
42 * work for me. This should be changed in the future, though. |
|
43 */ |
|
44 - (void)locationManager:(CLLocationManager*)aManager |
|
45 didUpdateToLocation:(CLLocation *)aNewLocation |
|
46 fromLocation:(CLLocation *)aOldLocation; |
|
47 @end |
|
48 |
|
49 @implementation LocationDelegate |
|
50 - (id) init:(CoreLocationLocationProvider*) aProvider |
|
51 { |
|
52 if (self = [super init]) { |
|
53 mProvider = aProvider; |
|
54 } |
|
55 |
|
56 return self; |
|
57 } |
|
58 |
|
59 - (void)locationManager:(CLLocationManager*)aManager |
|
60 didFailWithError:(NSError *)aError |
|
61 { |
|
62 nsCOMPtr<nsIConsoleService> console = |
|
63 do_GetService(NS_CONSOLESERVICE_CONTRACTID); |
|
64 |
|
65 NS_ENSURE_TRUE_VOID(console); |
|
66 |
|
67 NSString* message = |
|
68 [@"Failed to acquire position: " stringByAppendingString: [aError localizedDescription]]; |
|
69 |
|
70 console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get()); |
|
71 |
|
72 uint16_t err = nsIDOMGeoPositionError::POSITION_UNAVAILABLE; |
|
73 if ([aError code] == kCLErrorDenied) { |
|
74 err = nsIDOMGeoPositionError::PERMISSION_DENIED; |
|
75 } |
|
76 |
|
77 mProvider->NotifyError(err); |
|
78 } |
|
79 |
|
80 - (void)locationManager:(CLLocationManager*)aManager |
|
81 didUpdateToLocation:(CLLocation *)aNewLocation |
|
82 fromLocation:(CLLocation *)aOldLocation |
|
83 { |
|
84 nsCOMPtr<nsIDOMGeoPosition> geoPosition = |
|
85 new nsGeoPosition(aNewLocation.coordinate.latitude, |
|
86 aNewLocation.coordinate.longitude, |
|
87 aNewLocation.altitude, |
|
88 aNewLocation.horizontalAccuracy, |
|
89 aNewLocation.verticalAccuracy, |
|
90 aNewLocation.course, |
|
91 aNewLocation.speed, |
|
92 PR_Now()); |
|
93 |
|
94 mProvider->Update(geoPosition); |
|
95 } |
|
96 @end |
|
97 |
|
98 class CoreLocationObjects { |
|
99 public: |
|
100 NS_METHOD Init(CoreLocationLocationProvider* aProvider) { |
|
101 mLocationManager = [[CLLocationManager alloc] init]; |
|
102 NS_ENSURE_TRUE(mLocationManager, NS_ERROR_NOT_AVAILABLE); |
|
103 |
|
104 mLocationDelegate = [[LocationDelegate alloc] init:aProvider]; |
|
105 NS_ENSURE_TRUE(mLocationDelegate, NS_ERROR_NOT_AVAILABLE); |
|
106 |
|
107 mLocationManager.desiredAccuracy = kDEFAULT_ACCURACY; |
|
108 mLocationManager.delegate = mLocationDelegate; |
|
109 |
|
110 return NS_OK; |
|
111 } |
|
112 |
|
113 ~CoreLocationObjects() { |
|
114 if (mLocationManager) { |
|
115 [mLocationManager release]; |
|
116 } |
|
117 |
|
118 if (mLocationDelegate) { |
|
119 [mLocationDelegate release]; |
|
120 } |
|
121 } |
|
122 |
|
123 LocationDelegate* mLocationDelegate; |
|
124 CLLocationManager* mLocationManager; |
|
125 }; |
|
126 |
|
127 NS_IMPL_ISUPPORTS(CoreLocationLocationProvider, nsIGeolocationProvider) |
|
128 |
|
129 CoreLocationLocationProvider::CoreLocationLocationProvider() |
|
130 : mCLObjects(nullptr) |
|
131 { |
|
132 } |
|
133 |
|
134 NS_IMETHODIMP |
|
135 CoreLocationLocationProvider::Startup() |
|
136 { |
|
137 if (!mCLObjects) { |
|
138 nsAutoPtr<CoreLocationObjects> clObjs(new CoreLocationObjects()); |
|
139 |
|
140 nsresult rv = clObjs->Init(this); |
|
141 NS_ENSURE_SUCCESS(rv, rv); |
|
142 |
|
143 mCLObjects = clObjs.forget(); |
|
144 } |
|
145 |
|
146 [mCLObjects->mLocationManager startUpdatingLocation]; |
|
147 return NS_OK; |
|
148 } |
|
149 |
|
150 NS_IMETHODIMP |
|
151 CoreLocationLocationProvider::Watch(nsIGeolocationUpdate* aCallback) |
|
152 { |
|
153 if (mCallback) { |
|
154 return NS_OK; |
|
155 } |
|
156 |
|
157 mCallback = aCallback; |
|
158 return NS_OK; |
|
159 } |
|
160 |
|
161 NS_IMETHODIMP |
|
162 CoreLocationLocationProvider::Shutdown() |
|
163 { |
|
164 NS_ENSURE_STATE(mCLObjects); |
|
165 |
|
166 [mCLObjects->mLocationManager stopUpdatingLocation]; |
|
167 |
|
168 delete mCLObjects; |
|
169 mCLObjects = nullptr; |
|
170 return NS_OK; |
|
171 } |
|
172 |
|
173 NS_IMETHODIMP |
|
174 CoreLocationLocationProvider::SetHighAccuracy(bool aEnable) |
|
175 { |
|
176 NS_ENSURE_STATE(mCLObjects); |
|
177 |
|
178 mCLObjects->mLocationManager.desiredAccuracy = |
|
179 (aEnable ? kHIGH_ACCURACY : kDEFAULT_ACCURACY); |
|
180 |
|
181 return NS_OK; |
|
182 } |
|
183 |
|
184 void |
|
185 CoreLocationLocationProvider::Update(nsIDOMGeoPosition* aSomewhere) |
|
186 { |
|
187 if (aSomewhere && mCallback) { |
|
188 mCallback->Update(aSomewhere); |
|
189 } |
|
190 } |
|
191 |
|
192 void |
|
193 CoreLocationLocationProvider::NotifyError(uint16_t aErrorCode) |
|
194 { |
|
195 mCallback->NotifyError(aErrorCode); |
|
196 } |