mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 20:30:41 +00:00
Bug 715788 - Add A-GPS support for gonk. r=dougt
This commit is contained in:
parent
a91837d290
commit
8a5584b12b
@ -6,14 +6,26 @@
|
||||
#include <pthread.h>
|
||||
#include <hardware/gps.h>
|
||||
|
||||
#include "GonkGPSGeolocationProvider.h"
|
||||
#include "SystemWorkerManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsGeoPosition.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsINetworkManager.h"
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "GonkGPSGeolocationProvider.h"
|
||||
|
||||
#ifdef AGPS_TYPE_INVALID
|
||||
#define AGPS_HAVE_DUAL_APN
|
||||
#endif
|
||||
|
||||
#define DEBUG_GPS 0
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(GonkGPSGeolocationProvider, nsIGeolocationProvider)
|
||||
static const int kDefaultPeriod = 1000; // ms
|
||||
|
||||
NS_IMPL_ISUPPORTS2(GonkGPSGeolocationProvider, nsIGeolocationProvider, nsIRILDataCallback)
|
||||
|
||||
GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton;
|
||||
GpsCallbacks GonkGPSGeolocationProvider::mCallbacks = {
|
||||
@ -31,6 +43,19 @@ GpsCallbacks GonkGPSGeolocationProvider::mCallbacks = {
|
||||
#endif
|
||||
};
|
||||
|
||||
AGpsCallbacks
|
||||
GonkGPSGeolocationProvider::mAGPSCallbacks = {
|
||||
AGPSStatusCallback,
|
||||
CreateThreadCallback,
|
||||
};
|
||||
|
||||
AGpsRilCallbacks
|
||||
GonkGPSGeolocationProvider::mAGPSRILCallbacks = {
|
||||
AGPSRILSetIDCallback,
|
||||
AGPSRILRefLocCallback,
|
||||
CreateThreadCallback,
|
||||
};
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
|
||||
{
|
||||
@ -76,11 +101,30 @@ GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info)
|
||||
void
|
||||
GonkGPSGeolocationProvider::NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length)
|
||||
{
|
||||
#if DEBUG_GPS
|
||||
printf_stderr("*** nmea info\n");
|
||||
printf_stderr("timestamp:\t%lld\n", timestamp);
|
||||
printf_stderr("nmea: \t%s\n", nmea);
|
||||
printf_stderr("length: \t%d\n", length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities)
|
||||
{
|
||||
// Called by GPS engine in init(), hence we don't have to
|
||||
// protect the memebers
|
||||
|
||||
nsRefPtr<GonkGPSGeolocationProvider> provider =
|
||||
GonkGPSGeolocationProvider::GetSingleton();
|
||||
|
||||
provider->mSupportsScheduling = capabilities & GPS_CAPABILITY_SCHEDULING;
|
||||
provider->mSupportsMSB = capabilities & GPS_CAPABILITY_MSB;
|
||||
provider->mSupportsMSA = capabilities & GPS_CAPABILITY_MSA;
|
||||
provider->mSupportsSingleShot = capabilities & GPS_CAPABILITY_SINGLE_SHOT;
|
||||
#ifdef GPS_CAPABILITY_ON_DEMAND_TIME
|
||||
provider->mSupportsTimeInjection = capabilities & GPS_CAPABILITY_ON_DEMAND_TIME;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -118,8 +162,69 @@ GonkGPSGeolocationProvider::RequestUtcTimeCallback()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::AGPSStatusCallback(AGpsStatus* status)
|
||||
{
|
||||
MOZ_ASSERT(status);
|
||||
|
||||
nsRefPtr<GonkGPSGeolocationProvider> provider =
|
||||
GonkGPSGeolocationProvider::GetSingleton();
|
||||
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
switch (status->status) {
|
||||
case GPS_REQUEST_AGPS_DATA_CONN:
|
||||
event = NS_NewRunnableMethod(provider, &GonkGPSGeolocationProvider::RequestDataConnection);
|
||||
break;
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
event = NS_NewRunnableMethod(provider, &GonkGPSGeolocationProvider::ReleaseDataConnection);
|
||||
break;
|
||||
}
|
||||
if (event) {
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::AGPSRILSetIDCallback(uint32_t flags)
|
||||
{
|
||||
class RequestSetIDEvent : public nsRunnable {
|
||||
public:
|
||||
RequestSetIDEvent(uint32_t flags)
|
||||
: mFlags(flags)
|
||||
{}
|
||||
NS_IMETHOD Run() {
|
||||
nsRefPtr<GonkGPSGeolocationProvider> provider =
|
||||
GonkGPSGeolocationProvider::GetSingleton();
|
||||
provider->RequestSetID(mFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
uint32_t mFlags;
|
||||
};
|
||||
|
||||
NS_DispatchToMainThread(new RequestSetIDEvent(flags));
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::AGPSRILRefLocCallback(uint32_t flags)
|
||||
{
|
||||
nsRefPtr<GonkGPSGeolocationProvider> provider =
|
||||
GonkGPSGeolocationProvider::GetSingleton();
|
||||
|
||||
if (flags & AGPS_RIL_REQUEST_REFLOC_CELLID) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(provider, &GonkGPSGeolocationProvider::SetReferenceLocation);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
|
||||
: mStarted(false)
|
||||
, mSupportsScheduling(false)
|
||||
, mSupportsMSB(false)
|
||||
, mSupportsMSA(false)
|
||||
, mSupportsSingleShot(false)
|
||||
, mSupportsTimeInjection(false)
|
||||
, mGpsInterface(nsnull)
|
||||
{
|
||||
}
|
||||
@ -161,6 +266,87 @@ GonkGPSGeolocationProvider::GetGPSInterface()
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::RequestDataConnection()
|
||||
{
|
||||
// TODO: Bug 772747 - We should ask NetworkManager or RIL to open
|
||||
// SUPL type connection for us.
|
||||
const nsAdoptingString& apnName = Preferences::GetString("geo.gps.apn.name");
|
||||
const nsAdoptingString& apnUser = Preferences::GetString("geo.gps.apn.user");
|
||||
const nsAdoptingString& apnPass = Preferences::GetString("geo.gps.apn.password");
|
||||
if (apnName && apnUser && apnPass) {
|
||||
mRIL->SetupDataCall(1 /* DATACALL_RADIOTECHNOLOGY_GSM */,
|
||||
apnName, apnUser, apnPass,
|
||||
3 /* DATACALL_AUTH_PAP_OR_CHAP */,
|
||||
NS_LITERAL_STRING("IP") /* pdptype */);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::ReleaseDataConnection()
|
||||
{
|
||||
mRIL->DeactivateDataCall(mCid, NS_LITERAL_STRING("Close SUPL session"));
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
AGpsSetIDType type = AGPS_SETID_TYPE_NONE;
|
||||
|
||||
nsCOMPtr<nsIRilContext> rilCtx;
|
||||
mRIL->GetRilContext(getter_AddRefs(rilCtx));
|
||||
|
||||
if (rilCtx) {
|
||||
nsCOMPtr<nsIICCRecords> icc;
|
||||
rilCtx->GetIcc(getter_AddRefs(icc));
|
||||
if (icc) {
|
||||
nsAutoString id;
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
|
||||
type = AGPS_SETID_TYPE_IMSI;
|
||||
icc->GetImsi(id);
|
||||
}
|
||||
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
|
||||
type = AGPS_SETID_TYPE_MSISDN;
|
||||
icc->GetMsisdn(id);
|
||||
}
|
||||
NS_ConvertUTF16toUTF8 idBytes(id);
|
||||
mAGpsRilInterface->set_set_id(type, idBytes.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::SetReferenceLocation()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIRilContext> rilCtx;
|
||||
mRIL->GetRilContext(getter_AddRefs(rilCtx));
|
||||
|
||||
AGpsRefLocation location;
|
||||
|
||||
// TODO: Bug 772750 - get mobile connection technology from rilcontext
|
||||
location.type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
|
||||
|
||||
if (rilCtx) {
|
||||
nsCOMPtr<nsIICCRecords> icc;
|
||||
rilCtx->GetIcc(getter_AddRefs(icc));
|
||||
if (icc) {
|
||||
icc->GetMcc(&location.u.cellID.mcc);
|
||||
icc->GetMnc(&location.u.cellID.mnc);
|
||||
}
|
||||
nsCOMPtr<nsICellLocation> cell;
|
||||
rilCtx->GetCell(getter_AddRefs(cell));
|
||||
if (cell) {
|
||||
cell->GetLac(&location.u.cellID.lac);
|
||||
cell->GetCid(&location.u.cellID.cid);
|
||||
}
|
||||
mAGpsRilInterface->set_ref_location(&location, sizeof(location));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::Init()
|
||||
{
|
||||
@ -176,23 +362,76 @@ GonkGPSGeolocationProvider::Init()
|
||||
return;
|
||||
}
|
||||
|
||||
mAGpsInterface =
|
||||
static_cast<const AGpsInterface*>(mGpsInterface->get_extension(AGPS_INTERFACE));
|
||||
if (mAGpsInterface) {
|
||||
mAGpsInterface->init(&mAGPSCallbacks);
|
||||
}
|
||||
|
||||
mAGpsRilInterface =
|
||||
static_cast<const AGpsRilInterface*>(mGpsInterface->get_extension(AGPS_RIL_INTERFACE));
|
||||
if (mAGpsRilInterface) {
|
||||
mAGpsRilInterface->init(&mAGPSRILCallbacks);
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS));
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::StartGPS()
|
||||
{
|
||||
PRInt32 update = Preferences::GetInt("geo.default.update", 1000);
|
||||
PRInt32 update = Preferences::GetInt("geo.default.update", kDefaultPeriod);
|
||||
|
||||
if (mSupportsMSA || mSupportsMSB) {
|
||||
SetupAGPS();
|
||||
}
|
||||
|
||||
int positionMode = GPS_POSITION_MODE_STANDALONE;
|
||||
bool singleShot = false;
|
||||
|
||||
// XXX: If we know this is a single shot request, use MSA can be faster.
|
||||
if (singleShot && mSupportsMSA) {
|
||||
positionMode = GPS_POSITION_MODE_MS_ASSISTED;
|
||||
} else if (mSupportsMSB) {
|
||||
positionMode = GPS_POSITION_MODE_MS_BASED;
|
||||
}
|
||||
if (!mSupportsScheduling) {
|
||||
update = kDefaultPeriod;
|
||||
}
|
||||
|
||||
mGpsInterface->set_position_mode(positionMode,
|
||||
GPS_POSITION_RECURRENCE_PERIODIC,
|
||||
update, 0, 0);
|
||||
#if DEBUG_GPS
|
||||
// Delete cached data
|
||||
mGpsInterface->delete_aiding_data(GPS_DELETE_ALL);
|
||||
#endif
|
||||
|
||||
mGpsInterface->start();
|
||||
}
|
||||
|
||||
void
|
||||
GonkGPSGeolocationProvider::SetupAGPS()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
const nsAdoptingCString& suplServer = Preferences::GetCString("geo.gps.supl_server");
|
||||
PRInt32 suplPort = Preferences::GetInt("geo.gps.supl_port", -1);
|
||||
if (!suplServer.IsEmpty() && suplPort > 0) {
|
||||
mAGpsInterface->set_server(AGPS_TYPE_SUPL, suplServer.get(), suplPort);
|
||||
} else {
|
||||
NS_WARNING("Cannot get SUPL server settings");
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup network state listener
|
||||
nsIInterfaceRequestor* ireq = dom::gonk::SystemWorkerManager::GetInterfaceRequestor();
|
||||
mRIL = do_GetInterface(ireq);
|
||||
mRIL->RegisterDataCallCallback(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GonkGPSGeolocationProvider::Startup()
|
||||
{
|
||||
@ -239,6 +478,10 @@ GonkGPSGeolocationProvider::ShutdownNow()
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRIL) {
|
||||
mRIL->UnregisterDataCallCallback(this);
|
||||
}
|
||||
|
||||
mGpsInterface->stop();
|
||||
mGpsInterface->cleanup();
|
||||
mStarted = false;
|
||||
@ -250,3 +493,56 @@ GonkGPSGeolocationProvider::SetHighAccuracy(bool)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/** nsIRILDataCallback interface **/
|
||||
|
||||
NS_IMETHODIMP
|
||||
GonkGPSGeolocationProvider::DataCallStateChanged(nsIRILDataCallInfo* aDataCall)
|
||||
{
|
||||
MOZ_ASSERT(aDataCall);
|
||||
nsCOMPtr<nsIRILDataCallInfo> datacall = aDataCall;
|
||||
|
||||
PRUint32 callState;
|
||||
nsresult rv = datacall->GetState(&callState);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString apn;
|
||||
rv = datacall->GetApn(apn);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = datacall->GetCid(mCid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ConvertUTF16toUTF8 currentApn(apn);
|
||||
const nsAdoptingCString& agpsApn = Preferences::GetCString("geo.gps.apn.name");
|
||||
|
||||
// TODO: Bug 772748 - handle data call failed case.
|
||||
if (currentApn == agpsApn) {
|
||||
switch (callState) {
|
||||
case nsINetworkInterface::NETWORK_STATE_CONNECTED:
|
||||
#ifdef AGPS_HAVE_DUAL_APN
|
||||
mAGpsInterface->data_conn_open(AGPS_TYPE_ANY,
|
||||
agpsApn.get(),
|
||||
AGPS_APN_BEARER_IPV4);
|
||||
#else
|
||||
mAGpsInterface->data_conn_open(agpsApn.get());
|
||||
#endif
|
||||
break;
|
||||
case nsINetworkInterface::NETWORK_STATE_DISCONNECTED:
|
||||
#ifdef AGPS_HAVE_DUAL_APN
|
||||
mAGpsInterface->data_conn_closed(AGPS_TYPE_ANY);
|
||||
#else
|
||||
mAGpsInterface->data_conn_closed();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GonkGPSGeolocationProvider::ReceiveDataCallList(nsIRILDataCallInfo** aDataCalls,
|
||||
PRUint32 aLength)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -6,15 +6,20 @@
|
||||
#define GonkGPSGeolocationProvider_h
|
||||
|
||||
#include <hardware/gps.h> // for GpsInterface
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIGeolocationProvider.h"
|
||||
#include "nsIRadioInterfaceLayer.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
class GonkGPSGeolocationProvider : public nsIGeolocationProvider
|
||||
, public nsIRILDataCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIGEOLOCATIONPROVIDER
|
||||
NS_DECL_NSIRILDATACALLBACK
|
||||
|
||||
static already_AddRefed<GonkGPSGeolocationProvider> GetSingleton();
|
||||
|
||||
@ -35,21 +40,42 @@ private:
|
||||
static void ReleaseWakelockCallback();
|
||||
static pthread_t CreateThreadCallback(const char* name, void (*start)(void*), void* arg);
|
||||
static void RequestUtcTimeCallback();
|
||||
static void AGPSStatusCallback(AGpsStatus* status);
|
||||
static void AGPSRILSetIDCallback(uint32_t flags);
|
||||
static void AGPSRILRefLocCallback(uint32_t flags);
|
||||
|
||||
static GpsCallbacks mCallbacks;
|
||||
static AGpsCallbacks mAGPSCallbacks;
|
||||
static AGpsRilCallbacks mAGPSRILCallbacks;
|
||||
|
||||
void Init();
|
||||
void SetupAGPS();
|
||||
void StartGPS();
|
||||
void ShutdownNow();
|
||||
void RequestDataConnection();
|
||||
void ReleaseDataConnection();
|
||||
void RequestSetID(uint32_t flags);
|
||||
void SetReferenceLocation();
|
||||
|
||||
const GpsInterface* GetGPSInterface();
|
||||
|
||||
static GonkGPSGeolocationProvider* sSingleton;
|
||||
|
||||
bool mStarted;
|
||||
|
||||
bool mSupportsScheduling;
|
||||
bool mSupportsMSB;
|
||||
bool mSupportsMSA;
|
||||
bool mSupportsSingleShot;
|
||||
bool mSupportsTimeInjection;
|
||||
|
||||
const GpsInterface* mGpsInterface;
|
||||
const AGpsInterface* mAGpsInterface;
|
||||
const AGpsRilInterface* mAGpsRilInterface;
|
||||
nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
|
||||
nsCOMPtr<nsIThread> mInitThread;
|
||||
nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
|
||||
nsAutoString mCid;
|
||||
};
|
||||
|
||||
#endif /* GonkGPSGeolocationProvider_h */
|
||||
|
Loading…
x
Reference in New Issue
Block a user