Bug 874996 - Part 2 - Issue error events for geolocation provider errors. r=jdm
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -308,38 +308,24 @@ nsGeolocationRequest::nsGeolocationReque
nsGeolocationRequest::~nsGeolocationRequest()
{
}
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGeolocationRequest)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
+ NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
NS_IMPL_CYCLE_COLLECTION_3(nsGeolocationRequest, mCallback, mErrorCallback, mLocator)
-
-void
-nsGeolocationRequest::NotifyError(int16_t errorCode)
-{
- MOZ_ASSERT(NS_IsMainThread());
-
- nsRefPtr<PositionError> positionError = new PositionError(mLocator, errorCode);
- if (!positionError) {
- return;
- }
-
- positionError->NotifyCallback(mErrorCallback);
-}
-
-
NS_IMETHODIMP
nsGeolocationRequest::Notify(nsITimer* aTimer)
{
MOZ_ASSERT(!mShutdown, "timeout after shutdown");
NotifyError(nsIDOMGeoPositionError::TIMEOUT);
if (!mIsWatchPositionRequest) {
Shutdown();
@@ -496,17 +482,17 @@ nsGeolocationRequest::SendLocation(nsIDO
nsRefPtr<Position> wrapped, cachedWrapper = mLocator->GetCachedPosition();
if (cachedWrapper && aPosition == cachedWrapper->GetWrappedGeoPosition()) {
wrapped = cachedWrapper;
} else if (aPosition) {
nsCOMPtr<nsIDOMGeoPositionCoords> coords;
aPosition->GetCoords(getter_AddRefs(coords));
if (coords) {
- wrapped = new Position(mLocator, aPosition);
+ wrapped = new Position(ToSupports(mLocator), aPosition);
}
}
if (!wrapped) {
NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
return;
}
@@ -540,21 +526,32 @@ nsIPrincipal*
nsGeolocationRequest::GetPrincipal()
{
if (!mLocator) {
return nullptr;
}
return mLocator->GetPrincipal();
}
-void
+NS_IMETHODIMP
nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
{
nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(aPosition, this);
NS_DispatchToMainThread(ev);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGeolocationRequest::NotifyError(uint16_t aErrorCode)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsRefPtr<PositionError> positionError = new PositionError(mLocator, aErrorCode);
+ positionError->NotifyCallback(mErrorCallback);
+ return NS_OK;
}
void
nsGeolocationRequest::Shutdown()
{
MOZ_ASSERT(!mShutdown, "request shutdown twice");
mShutdown = true;
@@ -772,16 +769,25 @@ nsGeolocationService::Update(nsIDOMGeoPo
SetCachedPosition(aSomewhere);
for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
mGeolocators[i]->Update(aSomewhere);
}
return NS_OK;
}
+NS_IMETHODIMP
+nsGeolocationService::NotifyError(uint16_t aErrorCode)
+{
+ for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
+ mGeolocators[i]->NotifyError(aErrorCode);
+ }
+
+ return NS_OK;
+}
void
nsGeolocationService::SetCachedPosition(nsIDOMGeoPosition* aPosition)
{
mLastPosition = aPosition;
}
nsIDOMGeoPosition*
@@ -814,18 +820,25 @@ nsGeolocationService::StartDevice(nsIPri
if (!obs) {
return NS_ERROR_FAILURE;
}
if (!mProvider) {
return NS_ERROR_FAILURE;
}
- mProvider->Startup();
- mProvider->Watch(this, aRequestPrivate);
+ nsresult rv;
+
+ if (NS_FAILED(rv = mProvider->Startup()) ||
+ NS_FAILED(rv = mProvider->Watch(this, aRequestPrivate))) {
+
+ NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE);
+ return rv;
+ }
+
obs->NotifyObservers(mProvider,
"geolocation-device-events",
NS_LITERAL_STRING("starting").get());
return NS_OK;
}
void
@@ -941,16 +954,17 @@ nsGeolocationService::RemoveLocator(Geol
////////////////////////////////////////////////////
// Geolocation
////////////////////////////////////////////////////
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Geolocation)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoGeolocation)
NS_INTERFACE_MAP_ENTRY(nsIDOMGeoGeolocation)
+ NS_INTERFACE_MAP_ENTRY(nsIGeolocationUpdate)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(Geolocation)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Geolocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Geolocation)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedPosition)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -1071,32 +1085,56 @@ Geolocation::RemoveRequest(nsGeolocation
(mPendingCallbacks.RemoveElement(aRequest) !=
mWatchingCallbacks.RemoveElement(aRequest));
// request must have been in one of the lists
MOZ_ASSERT(requestWasKnown);
unused << requestWasKnown;
}
-void
+NS_IMETHODIMP
Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
{
if (!WindowOwnerStillExists()) {
- return Shutdown();
+ Shutdown();
+ return NS_OK;
}
for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
mPendingCallbacks[i-1]->Update(aSomewhere);
RemoveRequest(mPendingCallbacks[i-1]);
}
// notify everyone that is watching
- for (uint32_t i = 0; i< mWatchingCallbacks.Length(); i++) {
+ for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
mWatchingCallbacks[i]->Update(aSomewhere);
}
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+Geolocation::NotifyError(uint16_t aErrorCode)
+{
+ if (!WindowOwnerStillExists()) {
+ Shutdown();
+ return NS_OK;
+ }
+
+ for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
+ mPendingCallbacks[i-1]->NotifyError(aErrorCode);
+ RemoveRequest(mPendingCallbacks[i-1]);
+ }
+
+ // notify everyone that is watching
+ for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
+ mWatchingCallbacks[i]->NotifyError(aErrorCode);
+ }
+
+ return NS_OK;
}
void
Geolocation::SetCachedPosition(Position* aPosition)
{
mCachedPosition = aPosition;
}
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -49,51 +49,48 @@ class Geolocation;
typedef CallbackObjectHolder<PositionCallback, nsIDOMGeoPositionCallback> GeoPositionCallback;
typedef CallbackObjectHolder<PositionErrorCallback, nsIDOMGeoPositionErrorCallback> GeoPositionErrorCallback;
}
}
class nsGeolocationRequest
: public nsIContentPermissionRequest
, public nsITimerCallback
+ , public nsIGeolocationUpdate
, public PCOMContentPermissionRequestChild
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_DECL_NSITIMERCALLBACK
+ NS_DECL_NSIGEOLOCATIONUPDATE
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGeolocationRequest, nsIContentPermissionRequest)
nsGeolocationRequest(mozilla::dom::Geolocation* locator,
const mozilla::dom::GeoPositionCallback& callback,
const mozilla::dom::GeoPositionErrorCallback& errorCallback,
mozilla::idl::GeoPositionOptions* aOptions,
bool watchPositionRequest = false,
int32_t watchId = 0);
void Shutdown();
- // Called by the geolocation device to notify that a location has changed.
- void Update(nsIDOMGeoPosition* aPosition);
-
void SendLocation(nsIDOMGeoPosition* location);
bool WantsHighAccuracy() {return mOptions && mOptions->enableHighAccuracy;}
void SetTimeoutTimer();
nsIPrincipal* GetPrincipal();
~nsGeolocationRequest();
virtual bool Recv__delete__(const bool& allow) MOZ_OVERRIDE;
virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
bool IsWatch() { return mIsWatchPositionRequest; }
int32_t WatchId() { return mWatchId; }
private:
-
- void NotifyError(int16_t errorCode);
bool mIsWatchPositionRequest;
nsCOMPtr<nsITimer> mTimeoutTimer;
mozilla::dom::GeoPositionCallback mCallback;
mozilla::dom::GeoPositionErrorCallback mErrorCallback;
nsAutoPtr<mozilla::idl::GeoPositionOptions> mOptions;
nsRefPtr<mozilla::dom::Geolocation> mLocator;
@@ -171,39 +168,38 @@ private:
namespace mozilla {
namespace dom {
/**
* Can return a geolocation info
*/
class Geolocation MOZ_FINAL : public nsIDOMGeoGeolocation,
- public nsWrapperCache
+ public nsIGeolocationUpdate,
+ public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Geolocation)
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Geolocation, nsIDOMGeoGeolocation)
+ NS_DECL_NSIGEOLOCATIONUPDATE
NS_DECL_NSIDOMGEOGEOLOCATION
Geolocation();
nsresult Init(nsIDOMWindow* contentDom=nullptr);
nsIDOMWindow* GetParentObject() const;
virtual JSObject* WrapObject(JSContext *aCtx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
int32_t WatchPosition(PositionCallback& aCallback, PositionErrorCallback* aErrorCallback, const PositionOptions& aOptions, ErrorResult& aRv);
void GetCurrentPosition(PositionCallback& aCallback, PositionErrorCallback* aErrorCallback, const PositionOptions& aOptions, ErrorResult& aRv);
- // Called by the geolocation device to notify that a location has changed.
- void Update(nsIDOMGeoPosition* aPosition);
-
void SetCachedPosition(Position* aPosition);
Position* GetCachedPosition();
// Returns true if any of the callbacks are repeating
bool HasActiveCallbacks();
// Register an allowed request
void NotifyAllowedRequest(nsGeolocationRequest* aRequest);
@@ -307,11 +303,17 @@ public:
void NotifyCallback(const GeoPositionErrorCallback& callback);
private:
~PositionError();
int16_t mCode;
nsRefPtr<Geolocation> mParent;
};
}
+
+inline nsISupports*
+ToSupports(dom::Geolocation* aGeolocation)
+{
+ return ToSupports(static_cast<nsIDOMGeoGeolocation*>(aGeolocation));
+}
}
#endif /* nsGeoLocation_h */
--- a/xpcom/system/nsIGeolocationProvider.idl
+++ b/xpcom/system/nsIGeolocationProvider.idl
@@ -12,25 +12,37 @@ interface nsIDOMElement;
interface nsIDOMGeoPosition;
interface nsIGeolocationPrompt;
/**
* Interface provides a way for a geolocation provider to
* notify the system that a new location is available.
*/
-[scriptable, uuid(B89D7227-9F04-4236-A582-25A3F2779D72)]
+[scriptable, uuid(f00ff730-acff-4e8c-9991-0d4c84ba0e10)]
interface nsIGeolocationUpdate : nsISupports {
/**
* Notify the geolocation service that a new geolocation
* has been discovered.
* This must be called on the main thread
*/
void update(in nsIDOMGeoPosition position);
+
+ /**
+ * Notify the geolocation service of an error.
+ * This must be called on the main thread.
+ * The parameter refers to one of the constants in the
+ * nsIDOMGeoPositionError interface.
+ * Use this to report spurious errors coming from the
+ * provider; for errors occurring inside the methods in
+ * the nsIGeolocationProvider interface, just use the return
+ * value.
+ */
+ void notifyError(in unsigned short error);
};
/**
* Interface provides location information to the nsGeolocator
* via the nsIDOMGeolocationCallback interface. After
* startup is called, any geo location change should call
* callback.update().