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

     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  */
    17 #include <pthread.h>
    18 #include <hardware/gps.h>
    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"
    33 #ifdef MOZ_B2G_RIL
    34 #include "nsIDOMIccInfo.h"
    35 #include "nsIDOMMobileConnection.h"
    36 #include "nsIRadioInterfaceLayer.h"
    37 #endif
    39 #define SETTING_DEBUG_ENABLED "geolocation.debugging.enabled"
    41 #ifdef AGPS_TYPE_INVALID
    42 #define AGPS_HAVE_DUAL_APN
    43 #endif
    45 #define FLUSH_AIDE_DATA 0
    47 using namespace mozilla;
    49 static const int kDefaultPeriod = 1000; // ms
    50 static int gGPSDebugging = false;
    52 static const char* kNetworkConnStateChangedTopic = "network-connection-state-changed";
    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)
    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 };
    78 #ifdef MOZ_B2G_RIL
    79 AGpsCallbacks
    80 GonkGPSGeolocationProvider::mAGPSCallbacks = {
    81   AGPSStatusCallback,
    82   CreateThreadCallback,
    83 };
    85 AGpsRilCallbacks
    86 GonkGPSGeolocationProvider::mAGPSRILCallbacks = {
    87   AGPSRILSetIDCallback,
    88   AGPSRILRefLocCallback,
    89   CreateThreadCallback,
    90 };
    91 #endif // MOZ_B2G_RIL
    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   };
   115   MOZ_ASSERT(location);
   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 }
   128 void
   129 GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status)
   130 {
   131 }
   133 void
   134 GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info)
   135 {
   136 }
   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 }
   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();
   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   };
   175   NS_DispatchToMainThread(new UpdateCapabilitiesEvent(capabilities));
   176 }
   178 void
   179 GonkGPSGeolocationProvider::AcquireWakelockCallback()
   180 {
   181 }
   183 void
   184 GonkGPSGeolocationProvider::ReleaseWakelockCallback()
   185 {
   186 }
   188 typedef void *(*pthread_func)(void *);
   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;
   198   pthread_attr_init(&attr);
   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);
   205   return thread;
   206 }
   208 void
   209 GonkGPSGeolocationProvider::RequestUtcTimeCallback()
   210 {
   211 }
   213 #ifdef MOZ_B2G_RIL
   214 void
   215 GonkGPSGeolocationProvider::AGPSStatusCallback(AGpsStatus* status)
   216 {
   217   MOZ_ASSERT(status);
   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();
   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   };
   242   NS_DispatchToMainThread(new AGPSStatusEvent(status->status));
   243 }
   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   };
   263   NS_DispatchToMainThread(new RequestSetIDEvent(flags));
   264 }
   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   };
   281   if (flags & AGPS_RIL_REQUEST_REFLOC_CELLID) {
   282     NS_DispatchToMainThread(new RequestRefLocEvent());
   283   }
   284 }
   285 #endif // MOZ_B2G_RIL
   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 }
   300 GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider()
   301 {
   302   MOZ_ASSERT(NS_IsMainThread());
   303   MOZ_ASSERT(!mStarted, "Must call Shutdown before destruction");
   305   sSingleton = nullptr;
   306 }
   308 already_AddRefed<GonkGPSGeolocationProvider>
   309 GonkGPSGeolocationProvider::GetSingleton()
   310 {
   311   MOZ_ASSERT(NS_IsMainThread());
   313   if (!sSingleton)
   314     sSingleton = new GonkGPSGeolocationProvider();
   316   nsRefPtr<GonkGPSGeolocationProvider> provider = sSingleton;
   317   return provider.forget();
   318 }
   320 const GpsInterface*
   321 GonkGPSGeolocationProvider::GetGPSInterface()
   322 {
   323   hw_module_t* module;
   325   if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module))
   326     return nullptr;
   328   hw_device_t* device;
   329   if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device))
   330     return nullptr;
   332   gps_device_t* gps_device = (gps_device_t *)device;
   333   const GpsInterface* result = gps_device->get_gps_interface(gps_device);
   335   if (result->size != sizeof(GpsInterface)) {
   336     return nullptr;
   337   }
   338   return result;
   339 }
   341 #ifdef MOZ_B2G_RIL
   342 int32_t
   343 GonkGPSGeolocationProvider::GetDataConnectionState()
   344 {
   345   if (!mRadioInterface) {
   346     return nsINetworkInterface::NETWORK_STATE_UNKNOWN;
   347   }
   349   int32_t state;
   350   mRadioInterface->GetDataCallStateByType(NS_LITERAL_STRING("supl"), &state);
   351   return state;
   352 }
   354 void
   355 GonkGPSGeolocationProvider::SetAGpsDataConn(nsAString& aApn)
   356 {
   357   MOZ_ASSERT(NS_IsMainThread());
   358   MOZ_ASSERT(mAGpsInterface);
   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 }
   379 #endif // MOZ_B2G_RIL
   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 }
   395 #ifdef MOZ_B2G_RIL
   396 void
   397 GonkGPSGeolocationProvider::RequestDataConnection()
   398 {
   399   MOZ_ASSERT(NS_IsMainThread());
   401   if (!mRadioInterface) {
   402     return;
   403   }
   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 }
   414 void
   415 GonkGPSGeolocationProvider::ReleaseDataConnection()
   416 {
   417   MOZ_ASSERT(NS_IsMainThread());
   419   if (!mRadioInterface) {
   420     return;
   421   }
   423   mRadioInterface->DeactivateDataCallByType(NS_LITERAL_STRING("supl"));
   424 }
   426 void
   427 GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
   428 {
   429   MOZ_ASSERT(NS_IsMainThread());
   431   if (!mRadioInterface) {
   432     return;
   433   }
   435   AGpsSetIDType type = AGPS_SETID_TYPE_NONE;
   437   nsCOMPtr<nsIRilContext> rilCtx;
   438   mRadioInterface->GetRilContext(getter_AddRefs(rilCtx));
   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     }
   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     }
   459     NS_ConvertUTF16toUTF8 idBytes(id);
   460     mAGpsRilInterface->set_set_id(type, idBytes.get());
   461   }
   462 }
   464 void
   465 GonkGPSGeolocationProvider::SetReferenceLocation()
   466 {
   467   MOZ_ASSERT(NS_IsMainThread());
   469   if (!mRadioInterface) {
   470     return;
   471   }
   473   nsCOMPtr<nsIRilContext> rilCtx;
   474   mRadioInterface->GetRilContext(getter_AddRefs(rilCtx));
   476   AGpsRefLocation location;
   478   // TODO: Bug 772750 - get mobile connection technology from rilcontext
   479   location.type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
   481   if (rilCtx) {
   482     nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
   483     rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
   484     if (iccInfo) {
   485       nsresult result;
   486       nsAutoString mcc, mnc;
   488       iccInfo->GetMcc(mcc);
   489       iccInfo->GetMnc(mnc);
   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       }
   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;
   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         }
   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 }
   533 #endif // MOZ_B2G_RIL
   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   }
   547   MOZ_ASSERT(NS_IsMainThread());
   548   if (!mGpsInterface) {
   549     return;
   550   }
   552   mGpsInterface->inject_location(latitude, longitude, accuracy);
   553 }
   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());
   561   mGpsInterface = GetGPSInterface();
   562   if (!mGpsInterface) {
   563     return;
   564   }
   566   if (mGpsInterface->init(&mCallbacks) != 0) {
   567     return;
   568   }
   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   }
   577   mAGpsRilInterface =
   578     static_cast<const AGpsRilInterface*>(mGpsInterface->get_extension(AGPS_RIL_INTERFACE));
   579   if (mAGpsRilInterface) {
   580     mAGpsRilInterface->init(&mAGPSRILCallbacks);
   581   }
   582 #endif
   584   NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS));
   585 }
   587 void
   588 GonkGPSGeolocationProvider::StartGPS()
   589 {
   590   MOZ_ASSERT(NS_IsMainThread());
   591   MOZ_ASSERT(mGpsInterface);
   593   int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod);
   595 #ifdef MOZ_B2G_RIL
   596   if (mSupportsMSA || mSupportsMSB) {
   597     SetupAGPS();
   598   }
   599 #endif
   601   int positionMode = GPS_POSITION_MODE_STANDALONE;
   602   bool singleShot = false;
   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   }
   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
   624   mGpsInterface->start();
   625 }
   627 #ifdef MOZ_B2G_RIL
   628 void
   629 GonkGPSGeolocationProvider::SetupAGPS()
   630 {
   631   MOZ_ASSERT(NS_IsMainThread());
   632   MOZ_ASSERT(mAGpsInterface);
   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   }
   643   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   644   if (obs) {
   645     obs->AddObserver(this, kNetworkConnStateChangedTopic, false);
   646   }
   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
   658 NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate,
   659                   nsIGeolocationUpdate)
   661 NS_IMETHODIMP
   662 GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position)
   663 {
   664   nsRefPtr<GonkGPSGeolocationProvider> provider =
   665     GonkGPSGeolocationProvider::GetSingleton();
   667   nsCOMPtr<nsIDOMGeoPositionCoords> coords;
   668   position->GetCoords(getter_AddRefs(coords));
   669   if (!coords) {
   670     return NS_ERROR_FAILURE;
   671   }
   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   }
   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 }
   688 NS_IMETHODIMP
   689 GonkGPSGeolocationProvider::NetworkLocationUpdate::LocationUpdatePending()
   690 {
   691   return NS_OK;
   692 }
   694 NS_IMETHODIMP
   695 GonkGPSGeolocationProvider::NetworkLocationUpdate::NotifyError(uint16_t error)
   696 {
   697   return NS_OK;
   698 }
   700 NS_IMETHODIMP
   701 GonkGPSGeolocationProvider::Startup()
   702 {
   703   MOZ_ASSERT(NS_IsMainThread());
   705   RequestSettingValue(SETTING_DEBUG_ENABLED);
   706   if (mStarted) {
   707     return NS_OK;
   708   }
   710   if (!mInitThread) {
   711     nsresult rv = NS_NewThread(getter_AddRefs(mInitThread));
   712     NS_ENSURE_SUCCESS(rv, rv);
   713   }
   715   mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init),
   716                         NS_DISPATCH_NORMAL);
   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   }
   727   mLastGPSDerivedLocationTime = 0;
   728   mStarted = true;
   729   return NS_OK;
   730 }
   732 NS_IMETHODIMP
   733 GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
   734 {
   735   MOZ_ASSERT(NS_IsMainThread());
   737   mLocationCallback = aCallback;
   738   return NS_OK;
   739 }
   741 NS_IMETHODIMP
   742 GonkGPSGeolocationProvider::Shutdown()
   743 {
   744   MOZ_ASSERT(NS_IsMainThread());
   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
   761   mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS),
   762                         NS_DISPATCH_NORMAL);
   764   return NS_OK;
   765 }
   767 void
   768 GonkGPSGeolocationProvider::ShutdownGPS()
   769 {
   770   MOZ_ASSERT(!mStarted, "Should only be called after Shutdown");
   772   if (mGpsInterface) {
   773     mGpsInterface->stop();
   774     mGpsInterface->cleanup();
   775   }
   776 }
   778 NS_IMETHODIMP
   779 GonkGPSGeolocationProvider::SetHighAccuracy(bool)
   780 {
   781   return NS_OK;
   782 }
   784 NS_IMETHODIMP
   785 GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
   786                                     const char* aTopic,
   787                                     const char16_t* aData)
   788 {
   789   MOZ_ASSERT(NS_IsMainThread());
   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     }
   798     RequestSettingValue("ril.supl.apn");
   799   }
   800 #endif
   802   return NS_OK;
   803 }
   805 /** nsISettingsServiceCallback **/
   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);
   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 }
   834 NS_IMETHODIMP
   835 GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage)
   836 {
   837   return NS_OK;
   838 }

mercurial