Bug 874996 - Part 2 - Issue error events for geolocation provider errors. r=jdm
authorGuilherme Gonçalves <ggp@mozilla.com>
Wed, 19 Jun 2013 12:08:11 -0700
changeset 135662 59e7f2102e169ffa1a9194ab474f3343ab3ef5e7
parent 135661 f1ce5983b2856cb151266643fac3d1f584b1224b
child 135663 aa1227e3d6ba690cfcdee85c9aa6518823fd3ebc
push idunknown
push userunknown
push dateunknown
reviewersjdm
bugs874996
milestone24.0a1
Bug 874996 - Part 2 - Issue error events for geolocation provider errors. r=jdm
dom/src/geolocation/nsGeolocation.cpp
dom/src/geolocation/nsGeolocation.h
xpcom/system/nsIGeolocationProvider.idl
--- 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().