dom/system/gonk/GonkGPSGeolocationProvider.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:560a36c073ad
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <pthread.h>
18 #include <hardware/gps.h>
19
20 #include "GonkGPSGeolocationProvider.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/Services.h"
23 #include "nsGeoPosition.h"
24 #include "nsIInterfaceRequestorUtils.h"
25 #include "nsINetworkManager.h"
26 #include "nsIObserverService.h"
27 #include "nsJSUtils.h"
28 #include "nsServiceManagerUtils.h"
29 #include "nsThreadUtils.h"
30 #include "nsContentUtils.h"
31 #include "prtime.h"
32
33 #ifdef MOZ_B2G_RIL
34 #include "nsIDOMIccInfo.h"
35 #include "nsIDOMMobileConnection.h"
36 #include "nsIRadioInterfaceLayer.h"
37 #endif
38
39 #define SETTING_DEBUG_ENABLED "geolocation.debugging.enabled"
40
41 #ifdef AGPS_TYPE_INVALID
42 #define AGPS_HAVE_DUAL_APN
43 #endif
44
45 #define FLUSH_AIDE_DATA 0
46
47 using namespace mozilla;
48
49 static const int kDefaultPeriod = 1000; // ms
50 static int gGPSDebugging = false;
51
52 static const char* kNetworkConnStateChangedTopic = "network-connection-state-changed";
53
54 // While most methods of GonkGPSGeolocationProvider should only be
55 // called from main thread, we deliberately put the Init and ShutdownGPS
56 // methods off main thread to avoid blocking.
57 NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider,
58 nsIGeolocationProvider,
59 nsIObserver,
60 nsISettingsServiceCallback)
61
62 /* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr;
63 GpsCallbacks GonkGPSGeolocationProvider::mCallbacks = {
64 sizeof(GpsCallbacks),
65 LocationCallback,
66 StatusCallback,
67 SvStatusCallback,
68 NmeaCallback,
69 SetCapabilitiesCallback,
70 AcquireWakelockCallback,
71 ReleaseWakelockCallback,
72 CreateThreadCallback,
73 #ifdef GPS_CAPABILITY_ON_DEMAND_TIME
74 RequestUtcTimeCallback,
75 #endif
76 };
77
78 #ifdef MOZ_B2G_RIL
79 AGpsCallbacks
80 GonkGPSGeolocationProvider::mAGPSCallbacks = {
81 AGPSStatusCallback,
82 CreateThreadCallback,
83 };
84
85 AGpsRilCallbacks
86 GonkGPSGeolocationProvider::mAGPSRILCallbacks = {
87 AGPSRILSetIDCallback,
88 AGPSRILRefLocCallback,
89 CreateThreadCallback,
90 };
91 #endif // MOZ_B2G_RIL
92
93 void
94 GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
95 {
96 class UpdateLocationEvent : public nsRunnable {
97 public:
98 UpdateLocationEvent(nsGeoPosition* aPosition)
99 : mPosition(aPosition)
100 {}
101 NS_IMETHOD Run() {
102 nsRefPtr<GonkGPSGeolocationProvider> provider =
103 GonkGPSGeolocationProvider::GetSingleton();
104 provider->mLastGPSDerivedLocationTime = PR_Now();
105 nsCOMPtr<nsIGeolocationUpdate> callback = provider->mLocationCallback;
106 if (callback) {
107 callback->Update(mPosition);
108 }
109 return NS_OK;
110 }
111 private:
112 nsRefPtr<nsGeoPosition> mPosition;
113 };
114
115 MOZ_ASSERT(location);
116
117 nsRefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude,
118 location->longitude,
119 location->altitude,
120 location->accuracy,
121 location->accuracy,
122 location->bearing,
123 location->speed,
124 location->timestamp);
125 NS_DispatchToMainThread(new UpdateLocationEvent(somewhere));
126 }
127
128 void
129 GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status)
130 {
131 }
132
133 void
134 GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info)
135 {
136 }
137
138 void
139 GonkGPSGeolocationProvider::NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length)
140 {
141 if (gGPSDebugging) {
142 nsContentUtils::LogMessageToConsole("NMEA: timestamp:\t%lld", timestamp);
143 nsContentUtils::LogMessageToConsole("NMEA: nmea: \t%s", nmea);
144 nsContentUtils::LogMessageToConsole("NMEA length: \%d", length);
145 }
146 }
147
148 void
149 GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities)
150 {
151 class UpdateCapabilitiesEvent : public nsRunnable {
152 public:
153 UpdateCapabilitiesEvent(uint32_t aCapabilities)
154 : mCapabilities(aCapabilities)
155 {}
156 NS_IMETHOD Run() {
157 nsRefPtr<GonkGPSGeolocationProvider> provider =
158 GonkGPSGeolocationProvider::GetSingleton();
159
160 provider->mSupportsScheduling = mCapabilities & GPS_CAPABILITY_SCHEDULING;
161 #ifdef MOZ_B2G_RIL
162 provider->mSupportsMSB = mCapabilities & GPS_CAPABILITY_MSB;
163 provider->mSupportsMSA = mCapabilities & GPS_CAPABILITY_MSA;
164 #endif
165 provider->mSupportsSingleShot = mCapabilities & GPS_CAPABILITY_SINGLE_SHOT;
166 #ifdef GPS_CAPABILITY_ON_DEMAND_TIME
167 provider->mSupportsTimeInjection = mCapabilities & GPS_CAPABILITY_ON_DEMAND_TIME;
168 #endif
169 return NS_OK;
170 }
171 private:
172 uint32_t mCapabilities;
173 };
174
175 NS_DispatchToMainThread(new UpdateCapabilitiesEvent(capabilities));
176 }
177
178 void
179 GonkGPSGeolocationProvider::AcquireWakelockCallback()
180 {
181 }
182
183 void
184 GonkGPSGeolocationProvider::ReleaseWakelockCallback()
185 {
186 }
187
188 typedef void *(*pthread_func)(void *);
189
190 /** Callback for creating a thread that can call into the JS codes.
191 */
192 pthread_t
193 GonkGPSGeolocationProvider::CreateThreadCallback(const char* name, void (*start)(void *), void* arg)
194 {
195 pthread_t thread;
196 pthread_attr_t attr;
197
198 pthread_attr_init(&attr);
199
200 /* Unfortunately pthread_create and the callback disagreed on what
201 * start function should return.
202 */
203 pthread_create(&thread, &attr, reinterpret_cast<pthread_func>(start), arg);
204
205 return thread;
206 }
207
208 void
209 GonkGPSGeolocationProvider::RequestUtcTimeCallback()
210 {
211 }
212
213 #ifdef MOZ_B2G_RIL
214 void
215 GonkGPSGeolocationProvider::AGPSStatusCallback(AGpsStatus* status)
216 {
217 MOZ_ASSERT(status);
218
219 class AGPSStatusEvent : public nsRunnable {
220 public:
221 AGPSStatusEvent(AGpsStatusValue aStatus)
222 : mStatus(aStatus)
223 {}
224 NS_IMETHOD Run() {
225 nsRefPtr<GonkGPSGeolocationProvider> provider =
226 GonkGPSGeolocationProvider::GetSingleton();
227
228 switch (mStatus) {
229 case GPS_REQUEST_AGPS_DATA_CONN:
230 provider->RequestDataConnection();
231 break;
232 case GPS_RELEASE_AGPS_DATA_CONN:
233 provider->ReleaseDataConnection();
234 break;
235 }
236 return NS_OK;
237 }
238 private:
239 AGpsStatusValue mStatus;
240 };
241
242 NS_DispatchToMainThread(new AGPSStatusEvent(status->status));
243 }
244
245 void
246 GonkGPSGeolocationProvider::AGPSRILSetIDCallback(uint32_t flags)
247 {
248 class RequestSetIDEvent : public nsRunnable {
249 public:
250 RequestSetIDEvent(uint32_t flags)
251 : mFlags(flags)
252 {}
253 NS_IMETHOD Run() {
254 nsRefPtr<GonkGPSGeolocationProvider> provider =
255 GonkGPSGeolocationProvider::GetSingleton();
256 provider->RequestSetID(mFlags);
257 return NS_OK;
258 }
259 private:
260 uint32_t mFlags;
261 };
262
263 NS_DispatchToMainThread(new RequestSetIDEvent(flags));
264 }
265
266 void
267 GonkGPSGeolocationProvider::AGPSRILRefLocCallback(uint32_t flags)
268 {
269 class RequestRefLocEvent : public nsRunnable {
270 public:
271 RequestRefLocEvent()
272 {}
273 NS_IMETHOD Run() {
274 nsRefPtr<GonkGPSGeolocationProvider> provider =
275 GonkGPSGeolocationProvider::GetSingleton();
276 provider->SetReferenceLocation();
277 return NS_OK;
278 }
279 };
280
281 if (flags & AGPS_RIL_REQUEST_REFLOC_CELLID) {
282 NS_DispatchToMainThread(new RequestRefLocEvent());
283 }
284 }
285 #endif // MOZ_B2G_RIL
286
287 GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
288 : mStarted(false)
289 , mSupportsScheduling(false)
290 #ifdef MOZ_B2G_RIL
291 , mSupportsMSB(false)
292 , mSupportsMSA(false)
293 #endif
294 , mSupportsSingleShot(false)
295 , mSupportsTimeInjection(false)
296 , mGpsInterface(nullptr)
297 {
298 }
299
300 GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider()
301 {
302 MOZ_ASSERT(NS_IsMainThread());
303 MOZ_ASSERT(!mStarted, "Must call Shutdown before destruction");
304
305 sSingleton = nullptr;
306 }
307
308 already_AddRefed<GonkGPSGeolocationProvider>
309 GonkGPSGeolocationProvider::GetSingleton()
310 {
311 MOZ_ASSERT(NS_IsMainThread());
312
313 if (!sSingleton)
314 sSingleton = new GonkGPSGeolocationProvider();
315
316 nsRefPtr<GonkGPSGeolocationProvider> provider = sSingleton;
317 return provider.forget();
318 }
319
320 const GpsInterface*
321 GonkGPSGeolocationProvider::GetGPSInterface()
322 {
323 hw_module_t* module;
324
325 if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module))
326 return nullptr;
327
328 hw_device_t* device;
329 if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device))
330 return nullptr;
331
332 gps_device_t* gps_device = (gps_device_t *)device;
333 const GpsInterface* result = gps_device->get_gps_interface(gps_device);
334
335 if (result->size != sizeof(GpsInterface)) {
336 return nullptr;
337 }
338 return result;
339 }
340
341 #ifdef MOZ_B2G_RIL
342 int32_t
343 GonkGPSGeolocationProvider::GetDataConnectionState()
344 {
345 if (!mRadioInterface) {
346 return nsINetworkInterface::NETWORK_STATE_UNKNOWN;
347 }
348
349 int32_t state;
350 mRadioInterface->GetDataCallStateByType(NS_LITERAL_STRING("supl"), &state);
351 return state;
352 }
353
354 void
355 GonkGPSGeolocationProvider::SetAGpsDataConn(nsAString& aApn)
356 {
357 MOZ_ASSERT(NS_IsMainThread());
358 MOZ_ASSERT(mAGpsInterface);
359
360 int32_t connectionState = GetDataConnectionState();
361 if (connectionState == nsINetworkInterface::NETWORK_STATE_CONNECTED) {
362 NS_ConvertUTF16toUTF8 apn(aApn);
363 #ifdef AGPS_HAVE_DUAL_APN
364 mAGpsInterface->data_conn_open(AGPS_TYPE_SUPL,
365 apn.get(),
366 AGPS_APN_BEARER_IPV4);
367 #else
368 mAGpsInterface->data_conn_open(apn.get());
369 #endif
370 } else if (connectionState == nsINetworkInterface::NETWORK_STATE_DISCONNECTED) {
371 #ifdef AGPS_HAVE_DUAL_APN
372 mAGpsInterface->data_conn_closed(AGPS_TYPE_SUPL);
373 #else
374 mAGpsInterface->data_conn_closed();
375 #endif
376 }
377 }
378
379 #endif // MOZ_B2G_RIL
380
381 void
382 GonkGPSGeolocationProvider::RequestSettingValue(char* aKey)
383 {
384 MOZ_ASSERT(aKey);
385 nsCOMPtr<nsISettingsService> ss = do_GetService("@mozilla.org/settingsService;1");
386 if (!ss) {
387 MOZ_ASSERT(ss);
388 return;
389 }
390 nsCOMPtr<nsISettingsServiceLock> lock;
391 ss->CreateLock(nullptr, getter_AddRefs(lock));
392 lock->Get(aKey, this);
393 }
394
395 #ifdef MOZ_B2G_RIL
396 void
397 GonkGPSGeolocationProvider::RequestDataConnection()
398 {
399 MOZ_ASSERT(NS_IsMainThread());
400
401 if (!mRadioInterface) {
402 return;
403 }
404
405 if (GetDataConnectionState() == nsINetworkInterface::NETWORK_STATE_CONNECTED) {
406 // Connection is already established, we don't need to setup again.
407 // We just get supl APN and make AGPS data connection state updated.
408 RequestSettingValue("ril.supl.apn");
409 } else {
410 mRadioInterface->SetupDataCallByType(NS_LITERAL_STRING("supl"));
411 }
412 }
413
414 void
415 GonkGPSGeolocationProvider::ReleaseDataConnection()
416 {
417 MOZ_ASSERT(NS_IsMainThread());
418
419 if (!mRadioInterface) {
420 return;
421 }
422
423 mRadioInterface->DeactivateDataCallByType(NS_LITERAL_STRING("supl"));
424 }
425
426 void
427 GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
428 {
429 MOZ_ASSERT(NS_IsMainThread());
430
431 if (!mRadioInterface) {
432 return;
433 }
434
435 AGpsSetIDType type = AGPS_SETID_TYPE_NONE;
436
437 nsCOMPtr<nsIRilContext> rilCtx;
438 mRadioInterface->GetRilContext(getter_AddRefs(rilCtx));
439
440 if (rilCtx) {
441 nsAutoString id;
442 if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
443 type = AGPS_SETID_TYPE_IMSI;
444 rilCtx->GetImsi(id);
445 }
446
447 if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
448 nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
449 rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
450 if (iccInfo) {
451 nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
452 if (gsmIccInfo) {
453 type = AGPS_SETID_TYPE_MSISDN;
454 gsmIccInfo->GetMsisdn(id);
455 }
456 }
457 }
458
459 NS_ConvertUTF16toUTF8 idBytes(id);
460 mAGpsRilInterface->set_set_id(type, idBytes.get());
461 }
462 }
463
464 void
465 GonkGPSGeolocationProvider::SetReferenceLocation()
466 {
467 MOZ_ASSERT(NS_IsMainThread());
468
469 if (!mRadioInterface) {
470 return;
471 }
472
473 nsCOMPtr<nsIRilContext> rilCtx;
474 mRadioInterface->GetRilContext(getter_AddRefs(rilCtx));
475
476 AGpsRefLocation location;
477
478 // TODO: Bug 772750 - get mobile connection technology from rilcontext
479 location.type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
480
481 if (rilCtx) {
482 nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
483 rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
484 if (iccInfo) {
485 nsresult result;
486 nsAutoString mcc, mnc;
487
488 iccInfo->GetMcc(mcc);
489 iccInfo->GetMnc(mnc);
490
491 location.u.cellID.mcc = mcc.ToInteger(&result);
492 if (result != NS_OK) {
493 NS_WARNING("Cannot parse mcc to integer");
494 location.u.cellID.mcc = 0;
495 }
496
497 location.u.cellID.mnc = mnc.ToInteger(&result);
498 if (result != NS_OK) {
499 NS_WARNING("Cannot parse mnc to integer");
500 location.u.cellID.mnc = 0;
501 }
502 }
503 nsCOMPtr<nsIDOMMozMobileConnectionInfo> voice;
504 rilCtx->GetVoice(getter_AddRefs(voice));
505 if (voice) {
506 nsCOMPtr<nsIDOMMozMobileCellInfo> cell;
507 voice->GetCell(getter_AddRefs(cell));
508 if (cell) {
509 int32_t lac;
510 int64_t cid;
511
512 cell->GetGsmLocationAreaCode(&lac);
513 // The valid range of LAC is 0x0 to 0xffff which is defined in
514 // hardware/ril/include/telephony/ril.h
515 if (lac >= 0x0 && lac <= 0xffff) {
516 location.u.cellID.lac = lac;
517 }
518
519 cell->GetGsmCellId(&cid);
520 // The valid range of cell id is 0x0 to 0xffffffff which is defined in
521 // hardware/ril/include/telephony/ril.h
522 if (cid >= 0x0 && cid <= 0xffffffff) {
523 location.u.cellID.cid = cid;
524 }
525 }
526 }
527 if (mAGpsRilInterface) {
528 mAGpsRilInterface->set_ref_location(&location, sizeof(location));
529 }
530 }
531 }
532
533 #endif // MOZ_B2G_RIL
534
535 void
536 GonkGPSGeolocationProvider::InjectLocation(double latitude,
537 double longitude,
538 float accuracy)
539 {
540 if (gGPSDebugging) {
541 nsContentUtils::LogMessageToConsole("*** injecting location");
542 nsContentUtils::LogMessageToConsole("*** lat: %f", latitude);
543 nsContentUtils::LogMessageToConsole("*** lon: %f", longitude);
544 nsContentUtils::LogMessageToConsole("*** accuracy: %f", accuracy);
545 }
546
547 MOZ_ASSERT(NS_IsMainThread());
548 if (!mGpsInterface) {
549 return;
550 }
551
552 mGpsInterface->inject_location(latitude, longitude, accuracy);
553 }
554
555 void
556 GonkGPSGeolocationProvider::Init()
557 {
558 // Must not be main thread. Some GPS driver's first init takes very long.
559 MOZ_ASSERT(!NS_IsMainThread());
560
561 mGpsInterface = GetGPSInterface();
562 if (!mGpsInterface) {
563 return;
564 }
565
566 if (mGpsInterface->init(&mCallbacks) != 0) {
567 return;
568 }
569
570 #ifdef MOZ_B2G_RIL
571 mAGpsInterface =
572 static_cast<const AGpsInterface*>(mGpsInterface->get_extension(AGPS_INTERFACE));
573 if (mAGpsInterface) {
574 mAGpsInterface->init(&mAGPSCallbacks);
575 }
576
577 mAGpsRilInterface =
578 static_cast<const AGpsRilInterface*>(mGpsInterface->get_extension(AGPS_RIL_INTERFACE));
579 if (mAGpsRilInterface) {
580 mAGpsRilInterface->init(&mAGPSRILCallbacks);
581 }
582 #endif
583
584 NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS));
585 }
586
587 void
588 GonkGPSGeolocationProvider::StartGPS()
589 {
590 MOZ_ASSERT(NS_IsMainThread());
591 MOZ_ASSERT(mGpsInterface);
592
593 int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod);
594
595 #ifdef MOZ_B2G_RIL
596 if (mSupportsMSA || mSupportsMSB) {
597 SetupAGPS();
598 }
599 #endif
600
601 int positionMode = GPS_POSITION_MODE_STANDALONE;
602 bool singleShot = false;
603
604 #ifdef MOZ_B2G_RIL
605 // XXX: If we know this is a single shot request, use MSA can be faster.
606 if (singleShot && mSupportsMSA) {
607 positionMode = GPS_POSITION_MODE_MS_ASSISTED;
608 } else if (mSupportsMSB) {
609 positionMode = GPS_POSITION_MODE_MS_BASED;
610 }
611 #endif
612 if (!mSupportsScheduling) {
613 update = kDefaultPeriod;
614 }
615
616 mGpsInterface->set_position_mode(positionMode,
617 GPS_POSITION_RECURRENCE_PERIODIC,
618 update, 0, 0);
619 #if FLUSH_AIDE_DATA
620 // Delete cached data
621 mGpsInterface->delete_aiding_data(GPS_DELETE_ALL);
622 #endif
623
624 mGpsInterface->start();
625 }
626
627 #ifdef MOZ_B2G_RIL
628 void
629 GonkGPSGeolocationProvider::SetupAGPS()
630 {
631 MOZ_ASSERT(NS_IsMainThread());
632 MOZ_ASSERT(mAGpsInterface);
633
634 const nsAdoptingCString& suplServer = Preferences::GetCString("geo.gps.supl_server");
635 int32_t suplPort = Preferences::GetInt("geo.gps.supl_port", -1);
636 if (!suplServer.IsEmpty() && suplPort > 0) {
637 mAGpsInterface->set_server(AGPS_TYPE_SUPL, suplServer.get(), suplPort);
638 } else {
639 NS_WARNING("Cannot get SUPL server settings");
640 return;
641 }
642
643 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
644 if (obs) {
645 obs->AddObserver(this, kNetworkConnStateChangedTopic, false);
646 }
647
648 nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1");
649 if (ril) {
650 // TODO: Bug 878748 - B2G GPS: acquire correct RadioInterface instance in
651 // MultiSIM configuration
652 ril->GetRadioInterface(0 /* clientId */, getter_AddRefs(mRadioInterface));
653 }
654 }
655 #endif // MOZ_B2G_RIL
656
657
658 NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate,
659 nsIGeolocationUpdate)
660
661 NS_IMETHODIMP
662 GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position)
663 {
664 nsRefPtr<GonkGPSGeolocationProvider> provider =
665 GonkGPSGeolocationProvider::GetSingleton();
666
667 nsCOMPtr<nsIDOMGeoPositionCoords> coords;
668 position->GetCoords(getter_AddRefs(coords));
669 if (!coords) {
670 return NS_ERROR_FAILURE;
671 }
672
673 // if we haven't seen anything from the GPS device for 1s,
674 // use this network derived location.
675 int64_t diff = PR_Now() - provider->mLastGPSDerivedLocationTime;
676 if (provider->mLocationCallback && diff > kDefaultPeriod) {
677 provider->mLocationCallback->Update(position);
678 }
679
680 double lat, lon, acc;
681 coords->GetLatitude(&lat);
682 coords->GetLongitude(&lon);
683 coords->GetAccuracy(&acc);
684 provider->InjectLocation(lat, lon, acc);
685 return NS_OK;
686 }
687
688 NS_IMETHODIMP
689 GonkGPSGeolocationProvider::NetworkLocationUpdate::LocationUpdatePending()
690 {
691 return NS_OK;
692 }
693
694 NS_IMETHODIMP
695 GonkGPSGeolocationProvider::NetworkLocationUpdate::NotifyError(uint16_t error)
696 {
697 return NS_OK;
698 }
699
700 NS_IMETHODIMP
701 GonkGPSGeolocationProvider::Startup()
702 {
703 MOZ_ASSERT(NS_IsMainThread());
704
705 RequestSettingValue(SETTING_DEBUG_ENABLED);
706 if (mStarted) {
707 return NS_OK;
708 }
709
710 if (!mInitThread) {
711 nsresult rv = NS_NewThread(getter_AddRefs(mInitThread));
712 NS_ENSURE_SUCCESS(rv, rv);
713 }
714
715 mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init),
716 NS_DISPATCH_NORMAL);
717
718 mNetworkLocationProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1");
719 if (mNetworkLocationProvider) {
720 nsresult rv = mNetworkLocationProvider->Startup();
721 if (NS_SUCCEEDED(rv)) {
722 nsRefPtr<NetworkLocationUpdate> update = new NetworkLocationUpdate();
723 mNetworkLocationProvider->Watch(update);
724 }
725 }
726
727 mLastGPSDerivedLocationTime = 0;
728 mStarted = true;
729 return NS_OK;
730 }
731
732 NS_IMETHODIMP
733 GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
734 {
735 MOZ_ASSERT(NS_IsMainThread());
736
737 mLocationCallback = aCallback;
738 return NS_OK;
739 }
740
741 NS_IMETHODIMP
742 GonkGPSGeolocationProvider::Shutdown()
743 {
744 MOZ_ASSERT(NS_IsMainThread());
745
746 if (!mStarted) {
747 return NS_OK;
748 }
749 mStarted = false;
750 if (mNetworkLocationProvider) {
751 mNetworkLocationProvider->Shutdown();
752 mNetworkLocationProvider = nullptr;
753 }
754 #ifdef MOZ_B2G_RIL
755 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
756 if (obs) {
757 obs->RemoveObserver(this, kNetworkConnStateChangedTopic);
758 }
759 #endif
760
761 mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS),
762 NS_DISPATCH_NORMAL);
763
764 return NS_OK;
765 }
766
767 void
768 GonkGPSGeolocationProvider::ShutdownGPS()
769 {
770 MOZ_ASSERT(!mStarted, "Should only be called after Shutdown");
771
772 if (mGpsInterface) {
773 mGpsInterface->stop();
774 mGpsInterface->cleanup();
775 }
776 }
777
778 NS_IMETHODIMP
779 GonkGPSGeolocationProvider::SetHighAccuracy(bool)
780 {
781 return NS_OK;
782 }
783
784 NS_IMETHODIMP
785 GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
786 const char* aTopic,
787 const char16_t* aData)
788 {
789 MOZ_ASSERT(NS_IsMainThread());
790
791 #ifdef MOZ_B2G_RIL
792 if (!strcmp(aTopic, kNetworkConnStateChangedTopic)) {
793 nsCOMPtr<nsIRilNetworkInterface> iface = do_QueryInterface(aSubject);
794 if (!iface) {
795 return NS_OK;
796 }
797
798 RequestSettingValue("ril.supl.apn");
799 }
800 #endif
801
802 return NS_OK;
803 }
804
805 /** nsISettingsServiceCallback **/
806
807 NS_IMETHODIMP
808 GonkGPSGeolocationProvider::Handle(const nsAString& aName,
809 JS::Handle<JS::Value> aResult)
810 {
811 #ifdef MOZ_B2G_RIL
812 if (aName.EqualsLiteral("ril.supl.apn")) {
813 // When we get the APN, we attempt to call data_call_open of AGPS.
814 if (aResult.isString()) {
815 JSContext *cx = nsContentUtils::GetCurrentJSContext();
816 NS_ENSURE_TRUE(cx, NS_OK);
817
818 // NB: No need to enter a compartment to read the contents of a string.
819 nsDependentJSString apn;
820 apn.init(cx, aResult.toString());
821 if (!apn.IsEmpty()) {
822 SetAGpsDataConn(apn);
823 }
824 }
825 } else
826 #endif // MOZ_B2G_RIL
827 if (aName.EqualsLiteral(SETTING_DEBUG_ENABLED)) {
828 gGPSDebugging = aResult.isBoolean() ? aResult.toBoolean() : false;
829 return NS_OK;
830 }
831 return NS_OK;
832 }
833
834 NS_IMETHODIMP
835 GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage)
836 {
837 return NS_OK;
838 }

mercurial