1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,838 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* Copyright 2012 Mozilla Foundation and Mozilla contributors 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#include <pthread.h> 1.21 +#include <hardware/gps.h> 1.22 + 1.23 +#include "GonkGPSGeolocationProvider.h" 1.24 +#include "mozilla/Preferences.h" 1.25 +#include "mozilla/Services.h" 1.26 +#include "nsGeoPosition.h" 1.27 +#include "nsIInterfaceRequestorUtils.h" 1.28 +#include "nsINetworkManager.h" 1.29 +#include "nsIObserverService.h" 1.30 +#include "nsJSUtils.h" 1.31 +#include "nsServiceManagerUtils.h" 1.32 +#include "nsThreadUtils.h" 1.33 +#include "nsContentUtils.h" 1.34 +#include "prtime.h" 1.35 + 1.36 +#ifdef MOZ_B2G_RIL 1.37 +#include "nsIDOMIccInfo.h" 1.38 +#include "nsIDOMMobileConnection.h" 1.39 +#include "nsIRadioInterfaceLayer.h" 1.40 +#endif 1.41 + 1.42 +#define SETTING_DEBUG_ENABLED "geolocation.debugging.enabled" 1.43 + 1.44 +#ifdef AGPS_TYPE_INVALID 1.45 +#define AGPS_HAVE_DUAL_APN 1.46 +#endif 1.47 + 1.48 +#define FLUSH_AIDE_DATA 0 1.49 + 1.50 +using namespace mozilla; 1.51 + 1.52 +static const int kDefaultPeriod = 1000; // ms 1.53 +static int gGPSDebugging = false; 1.54 + 1.55 +static const char* kNetworkConnStateChangedTopic = "network-connection-state-changed"; 1.56 + 1.57 +// While most methods of GonkGPSGeolocationProvider should only be 1.58 +// called from main thread, we deliberately put the Init and ShutdownGPS 1.59 +// methods off main thread to avoid blocking. 1.60 +NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider, 1.61 + nsIGeolocationProvider, 1.62 + nsIObserver, 1.63 + nsISettingsServiceCallback) 1.64 + 1.65 +/* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr; 1.66 +GpsCallbacks GonkGPSGeolocationProvider::mCallbacks = { 1.67 + sizeof(GpsCallbacks), 1.68 + LocationCallback, 1.69 + StatusCallback, 1.70 + SvStatusCallback, 1.71 + NmeaCallback, 1.72 + SetCapabilitiesCallback, 1.73 + AcquireWakelockCallback, 1.74 + ReleaseWakelockCallback, 1.75 + CreateThreadCallback, 1.76 +#ifdef GPS_CAPABILITY_ON_DEMAND_TIME 1.77 + RequestUtcTimeCallback, 1.78 +#endif 1.79 +}; 1.80 + 1.81 +#ifdef MOZ_B2G_RIL 1.82 +AGpsCallbacks 1.83 +GonkGPSGeolocationProvider::mAGPSCallbacks = { 1.84 + AGPSStatusCallback, 1.85 + CreateThreadCallback, 1.86 +}; 1.87 + 1.88 +AGpsRilCallbacks 1.89 +GonkGPSGeolocationProvider::mAGPSRILCallbacks = { 1.90 + AGPSRILSetIDCallback, 1.91 + AGPSRILRefLocCallback, 1.92 + CreateThreadCallback, 1.93 +}; 1.94 +#endif // MOZ_B2G_RIL 1.95 + 1.96 +void 1.97 +GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location) 1.98 +{ 1.99 + class UpdateLocationEvent : public nsRunnable { 1.100 + public: 1.101 + UpdateLocationEvent(nsGeoPosition* aPosition) 1.102 + : mPosition(aPosition) 1.103 + {} 1.104 + NS_IMETHOD Run() { 1.105 + nsRefPtr<GonkGPSGeolocationProvider> provider = 1.106 + GonkGPSGeolocationProvider::GetSingleton(); 1.107 + provider->mLastGPSDerivedLocationTime = PR_Now(); 1.108 + nsCOMPtr<nsIGeolocationUpdate> callback = provider->mLocationCallback; 1.109 + if (callback) { 1.110 + callback->Update(mPosition); 1.111 + } 1.112 + return NS_OK; 1.113 + } 1.114 + private: 1.115 + nsRefPtr<nsGeoPosition> mPosition; 1.116 + }; 1.117 + 1.118 + MOZ_ASSERT(location); 1.119 + 1.120 + nsRefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude, 1.121 + location->longitude, 1.122 + location->altitude, 1.123 + location->accuracy, 1.124 + location->accuracy, 1.125 + location->bearing, 1.126 + location->speed, 1.127 + location->timestamp); 1.128 + NS_DispatchToMainThread(new UpdateLocationEvent(somewhere)); 1.129 +} 1.130 + 1.131 +void 1.132 +GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status) 1.133 +{ 1.134 +} 1.135 + 1.136 +void 1.137 +GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info) 1.138 +{ 1.139 +} 1.140 + 1.141 +void 1.142 +GonkGPSGeolocationProvider::NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length) 1.143 +{ 1.144 + if (gGPSDebugging) { 1.145 + nsContentUtils::LogMessageToConsole("NMEA: timestamp:\t%lld", timestamp); 1.146 + nsContentUtils::LogMessageToConsole("NMEA: nmea: \t%s", nmea); 1.147 + nsContentUtils::LogMessageToConsole("NMEA length: \%d", length); 1.148 + } 1.149 +} 1.150 + 1.151 +void 1.152 +GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities) 1.153 +{ 1.154 + class UpdateCapabilitiesEvent : public nsRunnable { 1.155 + public: 1.156 + UpdateCapabilitiesEvent(uint32_t aCapabilities) 1.157 + : mCapabilities(aCapabilities) 1.158 + {} 1.159 + NS_IMETHOD Run() { 1.160 + nsRefPtr<GonkGPSGeolocationProvider> provider = 1.161 + GonkGPSGeolocationProvider::GetSingleton(); 1.162 + 1.163 + provider->mSupportsScheduling = mCapabilities & GPS_CAPABILITY_SCHEDULING; 1.164 +#ifdef MOZ_B2G_RIL 1.165 + provider->mSupportsMSB = mCapabilities & GPS_CAPABILITY_MSB; 1.166 + provider->mSupportsMSA = mCapabilities & GPS_CAPABILITY_MSA; 1.167 +#endif 1.168 + provider->mSupportsSingleShot = mCapabilities & GPS_CAPABILITY_SINGLE_SHOT; 1.169 +#ifdef GPS_CAPABILITY_ON_DEMAND_TIME 1.170 + provider->mSupportsTimeInjection = mCapabilities & GPS_CAPABILITY_ON_DEMAND_TIME; 1.171 +#endif 1.172 + return NS_OK; 1.173 + } 1.174 + private: 1.175 + uint32_t mCapabilities; 1.176 + }; 1.177 + 1.178 + NS_DispatchToMainThread(new UpdateCapabilitiesEvent(capabilities)); 1.179 +} 1.180 + 1.181 +void 1.182 +GonkGPSGeolocationProvider::AcquireWakelockCallback() 1.183 +{ 1.184 +} 1.185 + 1.186 +void 1.187 +GonkGPSGeolocationProvider::ReleaseWakelockCallback() 1.188 +{ 1.189 +} 1.190 + 1.191 +typedef void *(*pthread_func)(void *); 1.192 + 1.193 +/** Callback for creating a thread that can call into the JS codes. 1.194 + */ 1.195 +pthread_t 1.196 +GonkGPSGeolocationProvider::CreateThreadCallback(const char* name, void (*start)(void *), void* arg) 1.197 +{ 1.198 + pthread_t thread; 1.199 + pthread_attr_t attr; 1.200 + 1.201 + pthread_attr_init(&attr); 1.202 + 1.203 + /* Unfortunately pthread_create and the callback disagreed on what 1.204 + * start function should return. 1.205 + */ 1.206 + pthread_create(&thread, &attr, reinterpret_cast<pthread_func>(start), arg); 1.207 + 1.208 + return thread; 1.209 +} 1.210 + 1.211 +void 1.212 +GonkGPSGeolocationProvider::RequestUtcTimeCallback() 1.213 +{ 1.214 +} 1.215 + 1.216 +#ifdef MOZ_B2G_RIL 1.217 +void 1.218 +GonkGPSGeolocationProvider::AGPSStatusCallback(AGpsStatus* status) 1.219 +{ 1.220 + MOZ_ASSERT(status); 1.221 + 1.222 + class AGPSStatusEvent : public nsRunnable { 1.223 + public: 1.224 + AGPSStatusEvent(AGpsStatusValue aStatus) 1.225 + : mStatus(aStatus) 1.226 + {} 1.227 + NS_IMETHOD Run() { 1.228 + nsRefPtr<GonkGPSGeolocationProvider> provider = 1.229 + GonkGPSGeolocationProvider::GetSingleton(); 1.230 + 1.231 + switch (mStatus) { 1.232 + case GPS_REQUEST_AGPS_DATA_CONN: 1.233 + provider->RequestDataConnection(); 1.234 + break; 1.235 + case GPS_RELEASE_AGPS_DATA_CONN: 1.236 + provider->ReleaseDataConnection(); 1.237 + break; 1.238 + } 1.239 + return NS_OK; 1.240 + } 1.241 + private: 1.242 + AGpsStatusValue mStatus; 1.243 + }; 1.244 + 1.245 + NS_DispatchToMainThread(new AGPSStatusEvent(status->status)); 1.246 +} 1.247 + 1.248 +void 1.249 +GonkGPSGeolocationProvider::AGPSRILSetIDCallback(uint32_t flags) 1.250 +{ 1.251 + class RequestSetIDEvent : public nsRunnable { 1.252 + public: 1.253 + RequestSetIDEvent(uint32_t flags) 1.254 + : mFlags(flags) 1.255 + {} 1.256 + NS_IMETHOD Run() { 1.257 + nsRefPtr<GonkGPSGeolocationProvider> provider = 1.258 + GonkGPSGeolocationProvider::GetSingleton(); 1.259 + provider->RequestSetID(mFlags); 1.260 + return NS_OK; 1.261 + } 1.262 + private: 1.263 + uint32_t mFlags; 1.264 + }; 1.265 + 1.266 + NS_DispatchToMainThread(new RequestSetIDEvent(flags)); 1.267 +} 1.268 + 1.269 +void 1.270 +GonkGPSGeolocationProvider::AGPSRILRefLocCallback(uint32_t flags) 1.271 +{ 1.272 + class RequestRefLocEvent : public nsRunnable { 1.273 + public: 1.274 + RequestRefLocEvent() 1.275 + {} 1.276 + NS_IMETHOD Run() { 1.277 + nsRefPtr<GonkGPSGeolocationProvider> provider = 1.278 + GonkGPSGeolocationProvider::GetSingleton(); 1.279 + provider->SetReferenceLocation(); 1.280 + return NS_OK; 1.281 + } 1.282 + }; 1.283 + 1.284 + if (flags & AGPS_RIL_REQUEST_REFLOC_CELLID) { 1.285 + NS_DispatchToMainThread(new RequestRefLocEvent()); 1.286 + } 1.287 +} 1.288 +#endif // MOZ_B2G_RIL 1.289 + 1.290 +GonkGPSGeolocationProvider::GonkGPSGeolocationProvider() 1.291 + : mStarted(false) 1.292 + , mSupportsScheduling(false) 1.293 +#ifdef MOZ_B2G_RIL 1.294 + , mSupportsMSB(false) 1.295 + , mSupportsMSA(false) 1.296 +#endif 1.297 + , mSupportsSingleShot(false) 1.298 + , mSupportsTimeInjection(false) 1.299 + , mGpsInterface(nullptr) 1.300 +{ 1.301 +} 1.302 + 1.303 +GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider() 1.304 +{ 1.305 + MOZ_ASSERT(NS_IsMainThread()); 1.306 + MOZ_ASSERT(!mStarted, "Must call Shutdown before destruction"); 1.307 + 1.308 + sSingleton = nullptr; 1.309 +} 1.310 + 1.311 +already_AddRefed<GonkGPSGeolocationProvider> 1.312 +GonkGPSGeolocationProvider::GetSingleton() 1.313 +{ 1.314 + MOZ_ASSERT(NS_IsMainThread()); 1.315 + 1.316 + if (!sSingleton) 1.317 + sSingleton = new GonkGPSGeolocationProvider(); 1.318 + 1.319 + nsRefPtr<GonkGPSGeolocationProvider> provider = sSingleton; 1.320 + return provider.forget(); 1.321 +} 1.322 + 1.323 +const GpsInterface* 1.324 +GonkGPSGeolocationProvider::GetGPSInterface() 1.325 +{ 1.326 + hw_module_t* module; 1.327 + 1.328 + if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module)) 1.329 + return nullptr; 1.330 + 1.331 + hw_device_t* device; 1.332 + if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device)) 1.333 + return nullptr; 1.334 + 1.335 + gps_device_t* gps_device = (gps_device_t *)device; 1.336 + const GpsInterface* result = gps_device->get_gps_interface(gps_device); 1.337 + 1.338 + if (result->size != sizeof(GpsInterface)) { 1.339 + return nullptr; 1.340 + } 1.341 + return result; 1.342 +} 1.343 + 1.344 +#ifdef MOZ_B2G_RIL 1.345 +int32_t 1.346 +GonkGPSGeolocationProvider::GetDataConnectionState() 1.347 +{ 1.348 + if (!mRadioInterface) { 1.349 + return nsINetworkInterface::NETWORK_STATE_UNKNOWN; 1.350 + } 1.351 + 1.352 + int32_t state; 1.353 + mRadioInterface->GetDataCallStateByType(NS_LITERAL_STRING("supl"), &state); 1.354 + return state; 1.355 +} 1.356 + 1.357 +void 1.358 +GonkGPSGeolocationProvider::SetAGpsDataConn(nsAString& aApn) 1.359 +{ 1.360 + MOZ_ASSERT(NS_IsMainThread()); 1.361 + MOZ_ASSERT(mAGpsInterface); 1.362 + 1.363 + int32_t connectionState = GetDataConnectionState(); 1.364 + if (connectionState == nsINetworkInterface::NETWORK_STATE_CONNECTED) { 1.365 + NS_ConvertUTF16toUTF8 apn(aApn); 1.366 +#ifdef AGPS_HAVE_DUAL_APN 1.367 + mAGpsInterface->data_conn_open(AGPS_TYPE_SUPL, 1.368 + apn.get(), 1.369 + AGPS_APN_BEARER_IPV4); 1.370 +#else 1.371 + mAGpsInterface->data_conn_open(apn.get()); 1.372 +#endif 1.373 + } else if (connectionState == nsINetworkInterface::NETWORK_STATE_DISCONNECTED) { 1.374 +#ifdef AGPS_HAVE_DUAL_APN 1.375 + mAGpsInterface->data_conn_closed(AGPS_TYPE_SUPL); 1.376 +#else 1.377 + mAGpsInterface->data_conn_closed(); 1.378 +#endif 1.379 + } 1.380 +} 1.381 + 1.382 +#endif // MOZ_B2G_RIL 1.383 + 1.384 +void 1.385 +GonkGPSGeolocationProvider::RequestSettingValue(char* aKey) 1.386 +{ 1.387 + MOZ_ASSERT(aKey); 1.388 + nsCOMPtr<nsISettingsService> ss = do_GetService("@mozilla.org/settingsService;1"); 1.389 + if (!ss) { 1.390 + MOZ_ASSERT(ss); 1.391 + return; 1.392 + } 1.393 + nsCOMPtr<nsISettingsServiceLock> lock; 1.394 + ss->CreateLock(nullptr, getter_AddRefs(lock)); 1.395 + lock->Get(aKey, this); 1.396 +} 1.397 + 1.398 +#ifdef MOZ_B2G_RIL 1.399 +void 1.400 +GonkGPSGeolocationProvider::RequestDataConnection() 1.401 +{ 1.402 + MOZ_ASSERT(NS_IsMainThread()); 1.403 + 1.404 + if (!mRadioInterface) { 1.405 + return; 1.406 + } 1.407 + 1.408 + if (GetDataConnectionState() == nsINetworkInterface::NETWORK_STATE_CONNECTED) { 1.409 + // Connection is already established, we don't need to setup again. 1.410 + // We just get supl APN and make AGPS data connection state updated. 1.411 + RequestSettingValue("ril.supl.apn"); 1.412 + } else { 1.413 + mRadioInterface->SetupDataCallByType(NS_LITERAL_STRING("supl")); 1.414 + } 1.415 +} 1.416 + 1.417 +void 1.418 +GonkGPSGeolocationProvider::ReleaseDataConnection() 1.419 +{ 1.420 + MOZ_ASSERT(NS_IsMainThread()); 1.421 + 1.422 + if (!mRadioInterface) { 1.423 + return; 1.424 + } 1.425 + 1.426 + mRadioInterface->DeactivateDataCallByType(NS_LITERAL_STRING("supl")); 1.427 +} 1.428 + 1.429 +void 1.430 +GonkGPSGeolocationProvider::RequestSetID(uint32_t flags) 1.431 +{ 1.432 + MOZ_ASSERT(NS_IsMainThread()); 1.433 + 1.434 + if (!mRadioInterface) { 1.435 + return; 1.436 + } 1.437 + 1.438 + AGpsSetIDType type = AGPS_SETID_TYPE_NONE; 1.439 + 1.440 + nsCOMPtr<nsIRilContext> rilCtx; 1.441 + mRadioInterface->GetRilContext(getter_AddRefs(rilCtx)); 1.442 + 1.443 + if (rilCtx) { 1.444 + nsAutoString id; 1.445 + if (flags & AGPS_RIL_REQUEST_SETID_IMSI) { 1.446 + type = AGPS_SETID_TYPE_IMSI; 1.447 + rilCtx->GetImsi(id); 1.448 + } 1.449 + 1.450 + if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) { 1.451 + nsCOMPtr<nsIDOMMozIccInfo> iccInfo; 1.452 + rilCtx->GetIccInfo(getter_AddRefs(iccInfo)); 1.453 + if (iccInfo) { 1.454 + nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo); 1.455 + if (gsmIccInfo) { 1.456 + type = AGPS_SETID_TYPE_MSISDN; 1.457 + gsmIccInfo->GetMsisdn(id); 1.458 + } 1.459 + } 1.460 + } 1.461 + 1.462 + NS_ConvertUTF16toUTF8 idBytes(id); 1.463 + mAGpsRilInterface->set_set_id(type, idBytes.get()); 1.464 + } 1.465 +} 1.466 + 1.467 +void 1.468 +GonkGPSGeolocationProvider::SetReferenceLocation() 1.469 +{ 1.470 + MOZ_ASSERT(NS_IsMainThread()); 1.471 + 1.472 + if (!mRadioInterface) { 1.473 + return; 1.474 + } 1.475 + 1.476 + nsCOMPtr<nsIRilContext> rilCtx; 1.477 + mRadioInterface->GetRilContext(getter_AddRefs(rilCtx)); 1.478 + 1.479 + AGpsRefLocation location; 1.480 + 1.481 + // TODO: Bug 772750 - get mobile connection technology from rilcontext 1.482 + location.type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 1.483 + 1.484 + if (rilCtx) { 1.485 + nsCOMPtr<nsIDOMMozIccInfo> iccInfo; 1.486 + rilCtx->GetIccInfo(getter_AddRefs(iccInfo)); 1.487 + if (iccInfo) { 1.488 + nsresult result; 1.489 + nsAutoString mcc, mnc; 1.490 + 1.491 + iccInfo->GetMcc(mcc); 1.492 + iccInfo->GetMnc(mnc); 1.493 + 1.494 + location.u.cellID.mcc = mcc.ToInteger(&result); 1.495 + if (result != NS_OK) { 1.496 + NS_WARNING("Cannot parse mcc to integer"); 1.497 + location.u.cellID.mcc = 0; 1.498 + } 1.499 + 1.500 + location.u.cellID.mnc = mnc.ToInteger(&result); 1.501 + if (result != NS_OK) { 1.502 + NS_WARNING("Cannot parse mnc to integer"); 1.503 + location.u.cellID.mnc = 0; 1.504 + } 1.505 + } 1.506 + nsCOMPtr<nsIDOMMozMobileConnectionInfo> voice; 1.507 + rilCtx->GetVoice(getter_AddRefs(voice)); 1.508 + if (voice) { 1.509 + nsCOMPtr<nsIDOMMozMobileCellInfo> cell; 1.510 + voice->GetCell(getter_AddRefs(cell)); 1.511 + if (cell) { 1.512 + int32_t lac; 1.513 + int64_t cid; 1.514 + 1.515 + cell->GetGsmLocationAreaCode(&lac); 1.516 + // The valid range of LAC is 0x0 to 0xffff which is defined in 1.517 + // hardware/ril/include/telephony/ril.h 1.518 + if (lac >= 0x0 && lac <= 0xffff) { 1.519 + location.u.cellID.lac = lac; 1.520 + } 1.521 + 1.522 + cell->GetGsmCellId(&cid); 1.523 + // The valid range of cell id is 0x0 to 0xffffffff which is defined in 1.524 + // hardware/ril/include/telephony/ril.h 1.525 + if (cid >= 0x0 && cid <= 0xffffffff) { 1.526 + location.u.cellID.cid = cid; 1.527 + } 1.528 + } 1.529 + } 1.530 + if (mAGpsRilInterface) { 1.531 + mAGpsRilInterface->set_ref_location(&location, sizeof(location)); 1.532 + } 1.533 + } 1.534 +} 1.535 + 1.536 +#endif // MOZ_B2G_RIL 1.537 + 1.538 +void 1.539 +GonkGPSGeolocationProvider::InjectLocation(double latitude, 1.540 + double longitude, 1.541 + float accuracy) 1.542 +{ 1.543 + if (gGPSDebugging) { 1.544 + nsContentUtils::LogMessageToConsole("*** injecting location"); 1.545 + nsContentUtils::LogMessageToConsole("*** lat: %f", latitude); 1.546 + nsContentUtils::LogMessageToConsole("*** lon: %f", longitude); 1.547 + nsContentUtils::LogMessageToConsole("*** accuracy: %f", accuracy); 1.548 + } 1.549 + 1.550 + MOZ_ASSERT(NS_IsMainThread()); 1.551 + if (!mGpsInterface) { 1.552 + return; 1.553 + } 1.554 + 1.555 + mGpsInterface->inject_location(latitude, longitude, accuracy); 1.556 +} 1.557 + 1.558 +void 1.559 +GonkGPSGeolocationProvider::Init() 1.560 +{ 1.561 + // Must not be main thread. Some GPS driver's first init takes very long. 1.562 + MOZ_ASSERT(!NS_IsMainThread()); 1.563 + 1.564 + mGpsInterface = GetGPSInterface(); 1.565 + if (!mGpsInterface) { 1.566 + return; 1.567 + } 1.568 + 1.569 + if (mGpsInterface->init(&mCallbacks) != 0) { 1.570 + return; 1.571 + } 1.572 + 1.573 +#ifdef MOZ_B2G_RIL 1.574 + mAGpsInterface = 1.575 + static_cast<const AGpsInterface*>(mGpsInterface->get_extension(AGPS_INTERFACE)); 1.576 + if (mAGpsInterface) { 1.577 + mAGpsInterface->init(&mAGPSCallbacks); 1.578 + } 1.579 + 1.580 + mAGpsRilInterface = 1.581 + static_cast<const AGpsRilInterface*>(mGpsInterface->get_extension(AGPS_RIL_INTERFACE)); 1.582 + if (mAGpsRilInterface) { 1.583 + mAGpsRilInterface->init(&mAGPSRILCallbacks); 1.584 + } 1.585 +#endif 1.586 + 1.587 + NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS)); 1.588 +} 1.589 + 1.590 +void 1.591 +GonkGPSGeolocationProvider::StartGPS() 1.592 +{ 1.593 + MOZ_ASSERT(NS_IsMainThread()); 1.594 + MOZ_ASSERT(mGpsInterface); 1.595 + 1.596 + int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod); 1.597 + 1.598 +#ifdef MOZ_B2G_RIL 1.599 + if (mSupportsMSA || mSupportsMSB) { 1.600 + SetupAGPS(); 1.601 + } 1.602 +#endif 1.603 + 1.604 + int positionMode = GPS_POSITION_MODE_STANDALONE; 1.605 + bool singleShot = false; 1.606 + 1.607 +#ifdef MOZ_B2G_RIL 1.608 + // XXX: If we know this is a single shot request, use MSA can be faster. 1.609 + if (singleShot && mSupportsMSA) { 1.610 + positionMode = GPS_POSITION_MODE_MS_ASSISTED; 1.611 + } else if (mSupportsMSB) { 1.612 + positionMode = GPS_POSITION_MODE_MS_BASED; 1.613 + } 1.614 +#endif 1.615 + if (!mSupportsScheduling) { 1.616 + update = kDefaultPeriod; 1.617 + } 1.618 + 1.619 + mGpsInterface->set_position_mode(positionMode, 1.620 + GPS_POSITION_RECURRENCE_PERIODIC, 1.621 + update, 0, 0); 1.622 +#if FLUSH_AIDE_DATA 1.623 + // Delete cached data 1.624 + mGpsInterface->delete_aiding_data(GPS_DELETE_ALL); 1.625 +#endif 1.626 + 1.627 + mGpsInterface->start(); 1.628 +} 1.629 + 1.630 +#ifdef MOZ_B2G_RIL 1.631 +void 1.632 +GonkGPSGeolocationProvider::SetupAGPS() 1.633 +{ 1.634 + MOZ_ASSERT(NS_IsMainThread()); 1.635 + MOZ_ASSERT(mAGpsInterface); 1.636 + 1.637 + const nsAdoptingCString& suplServer = Preferences::GetCString("geo.gps.supl_server"); 1.638 + int32_t suplPort = Preferences::GetInt("geo.gps.supl_port", -1); 1.639 + if (!suplServer.IsEmpty() && suplPort > 0) { 1.640 + mAGpsInterface->set_server(AGPS_TYPE_SUPL, suplServer.get(), suplPort); 1.641 + } else { 1.642 + NS_WARNING("Cannot get SUPL server settings"); 1.643 + return; 1.644 + } 1.645 + 1.646 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.647 + if (obs) { 1.648 + obs->AddObserver(this, kNetworkConnStateChangedTopic, false); 1.649 + } 1.650 + 1.651 + nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1"); 1.652 + if (ril) { 1.653 + // TODO: Bug 878748 - B2G GPS: acquire correct RadioInterface instance in 1.654 + // MultiSIM configuration 1.655 + ril->GetRadioInterface(0 /* clientId */, getter_AddRefs(mRadioInterface)); 1.656 + } 1.657 +} 1.658 +#endif // MOZ_B2G_RIL 1.659 + 1.660 + 1.661 +NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate, 1.662 + nsIGeolocationUpdate) 1.663 + 1.664 +NS_IMETHODIMP 1.665 +GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position) 1.666 +{ 1.667 + nsRefPtr<GonkGPSGeolocationProvider> provider = 1.668 + GonkGPSGeolocationProvider::GetSingleton(); 1.669 + 1.670 + nsCOMPtr<nsIDOMGeoPositionCoords> coords; 1.671 + position->GetCoords(getter_AddRefs(coords)); 1.672 + if (!coords) { 1.673 + return NS_ERROR_FAILURE; 1.674 + } 1.675 + 1.676 + // if we haven't seen anything from the GPS device for 1s, 1.677 + // use this network derived location. 1.678 + int64_t diff = PR_Now() - provider->mLastGPSDerivedLocationTime; 1.679 + if (provider->mLocationCallback && diff > kDefaultPeriod) { 1.680 + provider->mLocationCallback->Update(position); 1.681 + } 1.682 + 1.683 + double lat, lon, acc; 1.684 + coords->GetLatitude(&lat); 1.685 + coords->GetLongitude(&lon); 1.686 + coords->GetAccuracy(&acc); 1.687 + provider->InjectLocation(lat, lon, acc); 1.688 + return NS_OK; 1.689 +} 1.690 + 1.691 +NS_IMETHODIMP 1.692 +GonkGPSGeolocationProvider::NetworkLocationUpdate::LocationUpdatePending() 1.693 +{ 1.694 + return NS_OK; 1.695 +} 1.696 + 1.697 +NS_IMETHODIMP 1.698 +GonkGPSGeolocationProvider::NetworkLocationUpdate::NotifyError(uint16_t error) 1.699 +{ 1.700 + return NS_OK; 1.701 +} 1.702 + 1.703 +NS_IMETHODIMP 1.704 +GonkGPSGeolocationProvider::Startup() 1.705 +{ 1.706 + MOZ_ASSERT(NS_IsMainThread()); 1.707 + 1.708 + RequestSettingValue(SETTING_DEBUG_ENABLED); 1.709 + if (mStarted) { 1.710 + return NS_OK; 1.711 + } 1.712 + 1.713 + if (!mInitThread) { 1.714 + nsresult rv = NS_NewThread(getter_AddRefs(mInitThread)); 1.715 + NS_ENSURE_SUCCESS(rv, rv); 1.716 + } 1.717 + 1.718 + mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init), 1.719 + NS_DISPATCH_NORMAL); 1.720 + 1.721 + mNetworkLocationProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1"); 1.722 + if (mNetworkLocationProvider) { 1.723 + nsresult rv = mNetworkLocationProvider->Startup(); 1.724 + if (NS_SUCCEEDED(rv)) { 1.725 + nsRefPtr<NetworkLocationUpdate> update = new NetworkLocationUpdate(); 1.726 + mNetworkLocationProvider->Watch(update); 1.727 + } 1.728 + } 1.729 + 1.730 + mLastGPSDerivedLocationTime = 0; 1.731 + mStarted = true; 1.732 + return NS_OK; 1.733 +} 1.734 + 1.735 +NS_IMETHODIMP 1.736 +GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback) 1.737 +{ 1.738 + MOZ_ASSERT(NS_IsMainThread()); 1.739 + 1.740 + mLocationCallback = aCallback; 1.741 + return NS_OK; 1.742 +} 1.743 + 1.744 +NS_IMETHODIMP 1.745 +GonkGPSGeolocationProvider::Shutdown() 1.746 +{ 1.747 + MOZ_ASSERT(NS_IsMainThread()); 1.748 + 1.749 + if (!mStarted) { 1.750 + return NS_OK; 1.751 + } 1.752 + mStarted = false; 1.753 + if (mNetworkLocationProvider) { 1.754 + mNetworkLocationProvider->Shutdown(); 1.755 + mNetworkLocationProvider = nullptr; 1.756 + } 1.757 +#ifdef MOZ_B2G_RIL 1.758 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.759 + if (obs) { 1.760 + obs->RemoveObserver(this, kNetworkConnStateChangedTopic); 1.761 + } 1.762 +#endif 1.763 + 1.764 + mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS), 1.765 + NS_DISPATCH_NORMAL); 1.766 + 1.767 + return NS_OK; 1.768 +} 1.769 + 1.770 +void 1.771 +GonkGPSGeolocationProvider::ShutdownGPS() 1.772 +{ 1.773 + MOZ_ASSERT(!mStarted, "Should only be called after Shutdown"); 1.774 + 1.775 + if (mGpsInterface) { 1.776 + mGpsInterface->stop(); 1.777 + mGpsInterface->cleanup(); 1.778 + } 1.779 +} 1.780 + 1.781 +NS_IMETHODIMP 1.782 +GonkGPSGeolocationProvider::SetHighAccuracy(bool) 1.783 +{ 1.784 + return NS_OK; 1.785 +} 1.786 + 1.787 +NS_IMETHODIMP 1.788 +GonkGPSGeolocationProvider::Observe(nsISupports* aSubject, 1.789 + const char* aTopic, 1.790 + const char16_t* aData) 1.791 +{ 1.792 + MOZ_ASSERT(NS_IsMainThread()); 1.793 + 1.794 +#ifdef MOZ_B2G_RIL 1.795 + if (!strcmp(aTopic, kNetworkConnStateChangedTopic)) { 1.796 + nsCOMPtr<nsIRilNetworkInterface> iface = do_QueryInterface(aSubject); 1.797 + if (!iface) { 1.798 + return NS_OK; 1.799 + } 1.800 + 1.801 + RequestSettingValue("ril.supl.apn"); 1.802 + } 1.803 +#endif 1.804 + 1.805 + return NS_OK; 1.806 +} 1.807 + 1.808 +/** nsISettingsServiceCallback **/ 1.809 + 1.810 +NS_IMETHODIMP 1.811 +GonkGPSGeolocationProvider::Handle(const nsAString& aName, 1.812 + JS::Handle<JS::Value> aResult) 1.813 +{ 1.814 +#ifdef MOZ_B2G_RIL 1.815 + if (aName.EqualsLiteral("ril.supl.apn")) { 1.816 + // When we get the APN, we attempt to call data_call_open of AGPS. 1.817 + if (aResult.isString()) { 1.818 + JSContext *cx = nsContentUtils::GetCurrentJSContext(); 1.819 + NS_ENSURE_TRUE(cx, NS_OK); 1.820 + 1.821 + // NB: No need to enter a compartment to read the contents of a string. 1.822 + nsDependentJSString apn; 1.823 + apn.init(cx, aResult.toString()); 1.824 + if (!apn.IsEmpty()) { 1.825 + SetAGpsDataConn(apn); 1.826 + } 1.827 + } 1.828 + } else 1.829 +#endif // MOZ_B2G_RIL 1.830 + if (aName.EqualsLiteral(SETTING_DEBUG_ENABLED)) { 1.831 + gGPSDebugging = aResult.isBoolean() ? aResult.toBoolean() : false; 1.832 + return NS_OK; 1.833 + } 1.834 + return NS_OK; 1.835 +} 1.836 + 1.837 +NS_IMETHODIMP 1.838 +GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage) 1.839 +{ 1.840 + return NS_OK; 1.841 +}