dom/system/gonk/GonkGPSGeolocationProvider.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial