From a649a9687fae378d7c7949847f67b02de5ee327e Mon Sep 17 00:00:00 2001 From: Alphan Chen Date: Fri, 15 Jan 2016 10:32:24 +0800 Subject: [PATCH] Bug 853703 - Support SUPL NI. r=jaliu --- b2g/chrome/content/shell.js | 27 ++++ .../gonk/GonkGPSGeolocationProvider.cpp | 144 +++++++++++++++++- dom/system/gonk/GonkGPSGeolocationProvider.h | 5 + 3 files changed, 175 insertions(+), 1 deletion(-) diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index f43657a4b313..26ed117b488b 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -1137,6 +1137,33 @@ window.addEventListener('ContentStart', function update_onContentStart() { }, "geolocation-device-events", false); })(); +(function suplNiNotifyStatusTracker() { + Services.obs.addObserver(function(aSubject, aTopic, aData) { + shell.sendChromeEvent({ + type: 'supl-notification', + id: aData + }); +}, "supl-ni-notify", false); +})(); + +(function suplNiVerifyStatusTracker() { + Services.obs.addObserver(function(aSubject, aTopic, aData) { + shell.sendChromeEvent({ + type: 'supl-verification', + id: aData + }); +}, "supl-ni-verify", false); +})(); + +(function suplNiVerifyTimeoutStatusTracker() { + Services.obs.addObserver(function(aSubject, aTopic, aData) { + shell.sendChromeEvent({ + type: 'supl-verification-timeout', + id: aData + }); +}, "supl-ni-verify-timeout", false); +})(); + (function headphonesStatusTracker() { Services.obs.addObserver(function(aSubject, aTopic, aData) { shell.sendChromeEvent({ diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.cpp b/dom/system/gonk/GonkGPSGeolocationProvider.cpp index fa62d30c1d42..8812c3d2464d 100644 --- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp @@ -55,6 +55,15 @@ #endif #define FLUSH_AIDE_DATA 0 +#define SUPL_NI_NOTIFY "supl-ni-notify" +#define SUPL_NI_VERIFY "supl-ni-verify" +#define SUPL_NI_VERIFY_TIMEOUT "supl-ni-verify-timeout" +/* This flag is for sending chrome event to close the pop-up window. + The value is determined here which should not be used by GpsNiNotifyFlags. + GPS_NI_NEED_NOTIFY (0x0001) + GPS_NI_NEED_VERIFY (0x0002) + GPS_NI_PRIVACY_OVERRIDE (0x0004) */ +#define GPS_NI_NEED_TIMEOUT 0xFFFF using namespace mozilla; using namespace mozilla::dom; @@ -73,6 +82,10 @@ static const char* kSettingRilDefaultServiceId = "ril.data.defaultServiceId"; // Both of these settings can be toggled in the Gaia Developer settings screen. static const char* kSettingDebugEnabled = "geolocation.debugging.enabled"; static const char* kSettingDebugGpsIgnored = "geolocation.debugging.gps-locations-ignored"; +// Gaia will modify the value of settings key(supl.verification.choice) +// when user make his/her choice of SUPL NI verification. +static const char* kSettingSuplVerificationChoice = "supl.verification.choice"; + // While most methods of GonkGPSGeolocationProvider should only be // called from main thread, we deliberately put the Init and ShutdownGPS @@ -84,13 +97,17 @@ NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider, /* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr; GpsCallbacks GonkGPSGeolocationProvider::mCallbacks; +GpsNiCallbacks GonkGPSGeolocationProvider::mGPSNiCallbacks; +// This array is used for recording the request_id of replied SUPL NI request. +// In "TimeoutResponseEvent", we will check this array before replying the +// default response. +static nsTArray repliedSuplNiReqIds; #ifdef MOZ_B2G_RIL AGpsCallbacks GonkGPSGeolocationProvider::mAGPSCallbacks; AGpsRilCallbacks GonkGPSGeolocationProvider::mAGPSRILCallbacks; #endif // MOZ_B2G_RIL - void GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location) { @@ -327,6 +344,106 @@ GonkGPSGeolocationProvider::RequestUtcTimeCallback() { } +void +GonkGPSGeolocationProvider::SetNiResponse(int id, int response) +{ + MOZ_ASSERT(mGpsNiInterface); + mGpsNiInterface->respond(id, response); +} + +bool +GonkGPSGeolocationProvider::SendChromeEvent(int id, GpsNiNotifyFlags flags) +{ + MOZ_ASSERT(NS_IsMainThread()); + nsCOMPtr obs = services::GetObserverService(); + if (!obs) { + if (flags == GPS_NI_NEED_VERIFY) { + RefPtr provider = GonkGPSGeolocationProvider::GetSingleton(); + provider->SetNiResponse(id, GPS_NI_RESPONSE_NORESP); + } + return false; + } + + nsCString str = nsPrintfCString("%d", id); + if (flags == GPS_NI_NEED_NOTIFY) { + obs->NotifyObservers(nullptr, SUPL_NI_NOTIFY, NS_ConvertUTF8toUTF16(str).get()); + } else if (flags == GPS_NI_NEED_VERIFY) { + obs->NotifyObservers(nullptr, SUPL_NI_VERIFY, NS_ConvertUTF8toUTF16(str).get()); + } else if (flags == GPS_NI_NEED_TIMEOUT) { + obs->NotifyObservers(nullptr, SUPL_NI_VERIFY_TIMEOUT, NS_ConvertUTF8toUTF16(str).get()); + } + return true; +} + +void +GonkGPSGeolocationProvider::GPSNiNotifyCallback(GpsNiNotification *notification) +{ + + class GPSNiNotifyEvent : public nsRunnable { + public: + GPSNiNotifyEvent(GpsNiNotification *aNotification) + : mNotification(aNotification) + {} + NS_IMETHOD Run() { + int id = mNotification->notification_id; + GpsNiNotifyFlags flags = mNotification->notify_flags; + + if (gDebug_isLoggingEnabled) { + nsContentUtils::LogMessageToConsole( + "GPSNiNotifyCallback id:%d, flag:%x, timeout:%d, default response:%d\n", + id, flags, mNotification->timeout, mNotification->default_response); + } + + RefPtr provider = + GonkGPSGeolocationProvider::GetSingleton(); + + if(!provider->SendChromeEvent(id, flags)) { + nsContentUtils::LogMessageToConsole( + "SendChromeEvent Failed(id:%d, flags:%x)", id, flags); + return NS_OK; + } + + class TimeoutResponseEvent : public Task { + public: + TimeoutResponseEvent(int id, int defaultResp) + : mId(id), mDefaultResp(defaultResp) + {} + void Run() { + for (uint32_t idx = 0; idx < repliedSuplNiReqIds.Length() ; idx++) { + if(repliedSuplNiReqIds[idx] == mId) { + repliedSuplNiReqIds.RemoveElementAt(idx); + return; + } + } + RefPtr provider = + GonkGPSGeolocationProvider::GetSingleton(); + if (!provider->SendChromeEvent(mId, GPS_NI_NEED_TIMEOUT)) { + nsContentUtils::LogMessageToConsole( + "SendChromeEvent Failed(id:%d, flags:%x", mId, GPS_NI_NEED_TIMEOUT); + } + provider->SetNiResponse(mId, mDefaultResp); + return; + } + private: + int mId; + int mDefaultResp; + }; + + if (flags == GPS_NI_NEED_VERIFY) { + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new TimeoutResponseEvent(id, mNotification->default_response), + mNotification->timeout*1000); + } + return NS_OK; + } + private: + GpsNiNotification *mNotification; + }; + + NS_DispatchToMainThread(new GPSNiNotifyEvent(notification)); + return; +} + #ifdef MOZ_B2G_RIL void GonkGPSGeolocationProvider::AGPSStatusCallback(AGpsStatus* status) @@ -782,6 +899,9 @@ GonkGPSGeolocationProvider::Init() mCallbacks.request_utc_time_cb = RequestUtcTimeCallback; #endif + mGPSNiCallbacks.notify_cb = GPSNiNotifyCallback; + mGPSNiCallbacks.create_thread_cb = CreateThreadCallback; + #ifdef MOZ_B2G_RIL mAGPSCallbacks.status_cb = AGPSStatusCallback; mAGPSCallbacks.create_thread_cb = CreateThreadCallback; @@ -796,6 +916,12 @@ GonkGPSGeolocationProvider::Init() return; } + mGpsNiInterface = + static_cast(mGpsInterface->get_extension(GPS_NI_INTERFACE)); + if (mGpsNiInterface) { + mGpsNiInterface->init(&mGPSNiCallbacks); + } + #ifdef MOZ_B2G_RIL mAGpsInterface = static_cast(mGpsInterface->get_extension(AGPS_INTERFACE)); @@ -1198,6 +1324,22 @@ GonkGPSGeolocationProvider::Observe(nsISupports* aSubject, gDebug_isLoggingEnabled = setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; return NS_OK; + } else if (setting.mKey.EqualsASCII(kSettingSuplVerificationChoice)) { + nsContentUtils::LogMessageToConsole("geo: received the choice of supl ni verification\n"); + int id = setting.mValue.toNumber(); + RefPtr provider = + GonkGPSGeolocationProvider::GetSingleton(); + // The value of this key is based on notification_id: + // positive value(notification_id) means the choice is yes, + // negative value(notification_id * -1) means the choice is no. + if (id >= 0) { + provider->SetNiResponse(id, GPS_NI_RESPONSE_ACCEPT); + repliedSuplNiReqIds.AppendElement(id); + } else { + provider->SetNiResponse(id*-1, GPS_NI_RESPONSE_DENY); + repliedSuplNiReqIds.AppendElement(id*-1); + } + return NS_OK; } #ifdef MOZ_B2G_RIL else if (setting.mKey.EqualsASCII(kSettingRilDefaultServiceId)) { diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.h b/dom/system/gonk/GonkGPSGeolocationProvider.h index c839f00615ac..d48ff7d899ab 100644 --- a/dom/system/gonk/GonkGPSGeolocationProvider.h +++ b/dom/system/gonk/GonkGPSGeolocationProvider.h @@ -64,6 +64,7 @@ private: static void ReleaseWakelockCallback(); static pthread_t CreateThreadCallback(const char* name, void (*start)(void*), void* arg); static void RequestUtcTimeCallback(); + static void GPSNiNotifyCallback(GpsNiNotification *notification); #ifdef MOZ_B2G_RIL static void AGPSStatusCallback(AGpsStatus* status); static void AGPSRILSetIDCallback(uint32_t flags); @@ -71,6 +72,7 @@ private: #endif static GpsCallbacks mCallbacks; + static GpsNiCallbacks mGPSNiCallbacks; #ifdef MOZ_B2G_RIL static AGpsCallbacks mAGPSCallbacks; static AGpsRilCallbacks mAGPSRILCallbacks; @@ -81,6 +83,8 @@ private: void ShutdownGPS(); void InjectLocation(double latitude, double longitude, float accuracy); void RequestSettingValue(const char* aKey); + void SetNiResponse(int id, int response); + bool SendChromeEvent(int id, GpsNiNotifyFlags flags); #ifdef MOZ_B2G_RIL void UpdateRadioInterface(); bool IsValidRilServiceId(uint32_t aServiceId); @@ -115,6 +119,7 @@ private: bool mSupportsTimeInjection; const GpsInterface* mGpsInterface; + const GpsNiInterface* mGpsNiInterface; #ifdef MOZ_B2G_RIL const AGpsInterface* mAGpsInterface; const AGpsRilInterface* mAGpsRilInterface;