diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 6e289db6115..056549642be 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -512,22 +512,27 @@ ContentParent::RecvAsyncMessage(const nsString& aMsg, const nsString& aJSON) bool ContentParent::RecvGeolocationStart() { - nsCOMPtr geo = do_GetService("@mozilla.org/geolocation;1"); - if (!geo) { - return true; + if (mGeolocationWatchID == -1) { + nsCOMPtr geo = do_GetService("@mozilla.org/geolocation;1"); + if (!geo) { + return true; + } + geo->WatchPosition(this, nsnull, nsnull, &mGeolocationWatchID); } - geo->WatchPosition(this, nsnull, nsnull, &mGeolocationWatchID); return true; } bool ContentParent::RecvGeolocationStop() { - nsCOMPtr geo = do_GetService("@mozilla.org/geolocation;1"); - if (!geo) { - return true; + if (mGeolocationWatchID != -1) { + nsCOMPtr geo = do_GetService("@mozilla.org/geolocation;1"); + if (!geo) { + return true; + } + geo->ClearWatch(mGeolocationWatchID); + mGeolocationWatchID = -1; } - geo->ClearWatch(mGeolocationWatchID); return true; } diff --git a/dom/src/geolocation/nsGeolocation.cpp b/dom/src/geolocation/nsGeolocation.cpp index 38578100f83..9091f8c7930 100644 --- a/dom/src/geolocation/nsGeolocation.cpp +++ b/dom/src/geolocation/nsGeolocation.cpp @@ -741,6 +741,11 @@ nsGeolocationService::StartDevice() if (!sGeoEnabled) return NS_ERROR_NOT_AVAILABLE; + // we do not want to keep the geolocation devices online + // indefinitely. Close them down after a reasonable period of + // inactivivity + SetDisconnectTimer(); + #ifdef MOZ_IPC if (XRE_GetProcessType() == GeckoProcessType_Content) { ContentChild* cpc = ContentChild::GetSingleton(); @@ -750,26 +755,18 @@ nsGeolocationService::StartDevice() #endif // Start them up! - nsresult rv = NS_ERROR_NOT_AVAILABLE; - for (PRUint32 i = mProviders.Count() - 1; i != PRUint32(-1); --i) { - // If any provder gets started without error, go ahead - // and proceed without error - nsresult temp = mProviders[i]->Startup(); - if (NS_SUCCEEDED(temp)) { - rv = NS_OK; + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (!obs) + return NS_ERROR_FAILURE; - mProviders[i]->Watch(this); - } + for (PRUint32 i = 0; i < mProviders.Count(); i++) { + mProviders[i]->Startup(); + mProviders[i]->Watch(this); + obs->NotifyObservers(mProviders[i], + "geolocation-device-events", + NS_LITERAL_STRING("starting").get()); } - if (NS_FAILED(rv)) - return NS_ERROR_NOT_AVAILABLE; - - // we do not want to keep the geolocation devices online - // indefinitely. Close them down after a reasonable period of - // inactivivity - SetDisconnectTimer(); - return NS_OK; } @@ -802,8 +799,15 @@ nsGeolocationService::StopDevice() } #endif - for (PRUint32 i = mProviders.Count() - 1; i != PRUint32(-1); --i) { + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (!obs) + return; + + for (PRUint32 i = 0; i Shutdown(); + obs->NotifyObservers(mProviders[i], + "geolocation-device-events", + NS_LITERAL_STRING("shutdown").get()); } } @@ -944,7 +948,11 @@ nsGeolocation::Shutdown() PRBool nsGeolocation::HasActiveCallbacks() { - return mWatchingCallbacks.Length() != 0; + for (PRUint32 i = 0; i < mWatchingCallbacks.Length(); i++) + if (mWatchingCallbacks[i]->IsActive()) + return PR_TRUE; + + return PR_FALSE; } void diff --git a/dom/src/geolocation/nsGeolocation.h b/dom/src/geolocation/nsGeolocation.h index 89bb22447d6..2054ec920f8 100644 --- a/dom/src/geolocation/nsGeolocation.h +++ b/dom/src/geolocation/nsGeolocation.h @@ -97,6 +97,7 @@ class nsGeolocationRequest void SendLocation(nsIDOMGeoPosition* location); void MarkCleared(); + PRBool IsActive() {return !mCleared;} PRBool Allowed() {return mAllowed;} void SetTimeoutTimer(); diff --git a/dom/tests/unit/test_geolocation_provider.js b/dom/tests/unit/test_geolocation_provider.js new file mode 100644 index 00000000000..c283852f842 --- /dev/null +++ b/dom/tests/unit/test_geolocation_provider.js @@ -0,0 +1,41 @@ + +const Ci = Components.interfaces; +const Cc = Components.classes; + +function successCallback(pos){} + +var observer = { + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsISupports) || + iid.equals(Components.interfaces.nsIObserver)) + return this; + throw Components.results.NS_ERROR_NO_INTERFACE; + }, + + observe: function(subject, topic, data) { + if (data == "shutdown") { + do_check_true(1) + do_test_finished(); + } + else if (data == "starting") { + do_check_true(1) + } + + }, +}; + + +function run_test() +{ + // only kill this test when shutdown is called on the provider. + do_test_pending(); + + var obs = Cc["@mozilla.org/observer-service;1"].getService(); + obs = obs.QueryInterface(Ci.nsIObserverService); + obs.addObserver(observer, "geolocation-device-events", false); + + var geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsIDOMGeoGeolocation); + var watchID = geolocation.watchPosition(successCallback); + do_timeout(1000, function() { geolocation.clearWatch(watchID);}) +} +