dom/system/gonk/GonkGPSGeolocationProvider.cpp

changeset 0
6474c204b198
     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 +}

mercurial