Bug 735011 - geolocation - support enableHighAccuracy position option. r=dougt
authorJosh Dhaliwal <jdhaliwal@mozilla.com>
Wed, 21 Mar 2012 10:52:35 -0700
changeset 89943 e6083e4def5e717a953078383c989e150643c922
parent 89942 17b7af74d06902d34c85b7e8dc9d46d1ea6a5156
child 89944 a6cb28e6c61ccdbb3a46fb38ce6743261c30fc74
push idunknown
push userunknown
push dateunknown
reviewersdougt
bugs735011
milestone14.0a1
Bug 735011 - geolocation - support enableHighAccuracy position option. r=dougt
dom/src/geolocation/nsGeolocation.cpp
dom/src/geolocation/nsGeolocation.h
dom/system/NetworkGeolocationProvider.js
dom/system/android/AndroidLocationProvider.cpp
dom/system/gonk/GonkGPSGeolocationProvider.cpp
mobile/android/base/GeckoAppShell.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
xpcom/system/nsIGeolocationProvider.idl
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -380,16 +380,21 @@ nsGeolocationRequest::Allow()
   PRUint32 maximumAge = 30 * PR_MSEC_PER_SEC;
   if (mOptions) {
     PRInt32 tempAge;
     nsresult rv = mOptions->GetMaximumAge(&tempAge);
     if (NS_SUCCEEDED(rv)) {
       if (tempAge >= 0)
         maximumAge = tempAge;
     }
+    bool highAccuracy;
+    rv = mOptions->GetEnableHighAccuracy(&highAccuracy);
+    if (NS_SUCCEEDED(rv) && highAccuracy) {
+	geoService->SetHigherAccuracy(true);
+    }
   }
 
   if (lastPosition && maximumAge > 0 &&
       ( PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
         PRTime(cachedPositionTime) )) {
     // okay, we can return a cached position
     mAllowed = true;
     
@@ -475,16 +480,26 @@ nsGeolocationRequest::Update(nsIDOMGeoPo
                                    mIsWatchPositionRequest ? nsnull : mLocator);
   NS_DispatchToMainThread(ev);
   return true;
 }
 
 void
 nsGeolocationRequest::Shutdown()
 {
+  if (mOptions) {
+      bool highAccuracy;
+      nsresult rv = mOptions->GetEnableHighAccuracy(&highAccuracy);
+      if (NS_SUCCEEDED(rv) && highAccuracy) {
+	  nsRefPtr<nsGeolocationService> geoService = nsGeolocationService::GetInstance();
+	  if (geoService)
+	      geoService->SetHigherAccuracy(false);
+      }
+  }
+
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
     mTimeoutTimer = nsnull;
   }
   mCleared = true;
   mCallback = nsnull;
   mErrorCallback = nsnull;
 }
@@ -697,16 +712,34 @@ nsGeolocationService::SetDisconnectTimer
   else
     mDisconnectTimer->Cancel();
 
   mDisconnectTimer->Init(this,
                          sProviderTimeout,
                          nsITimer::TYPE_ONE_SHOT);
 }
 
+void
+nsGeolocationService::SetHigherAccuracy(bool aEnable)
+{
+    if (!mHigherAccuracy && aEnable) {
+	  for (PRInt32 i = 0; i < mProviders.Count(); i++) {
+	    mProviders[i]->SetHighAccuracy(true);
+	  }
+    }
+	
+    if (mHigherAccuracy && !aEnable) {
+	  for (PRInt32 i = 0; i < mProviders.Count(); i++) {
+	    mProviders[i]->SetHighAccuracy(false);
+	  }
+    }
+
+    mHigherAccuracy = aEnable;
+}
+
 void 
 nsGeolocationService::StopDevice()
 {
   if(mDisconnectTimer) {
     mDisconnectTimer->Cancel();
     mDisconnectTimer = nsnull;
   }
 
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -129,17 +129,19 @@ public:
   static nsGeolocationService* GetGeolocationService();
   static nsGeolocationService* GetInstance();  // Non-Addref'ing
   static nsGeolocationService* gService;
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIGEOLOCATIONUPDATE
   NS_DECL_NSIOBSERVER
 
-  nsGeolocationService() {}
+  nsGeolocationService() {
+      mHigherAccuracy = false;
+  }
 
   nsresult Init();
 
   // Management of the nsGeolocation objects
   void AddLocator(nsGeolocation* locator);
   void RemoveLocator(nsGeolocation* locator);
 
   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
@@ -149,16 +151,19 @@ public:
   nsresult StartDevice();
 
   // Stop the started geolocation device (gps, nmea, etc.)
   void     StopDevice();
   
   // create, or reinitalize the callback timer
   void     SetDisconnectTimer();
 
+  // request higher accuracy, if possible
+  void     SetHigherAccuracy(bool aEnable);
+
 private:
 
   ~nsGeolocationService();
 
   // Disconnect timer.  When this timer expires, it clears all pending callbacks
   // and closes down the provider, unless we are watching a point, and in that
   // case, we disable the disconnect timer.
   nsCOMPtr<nsITimer> mDisconnectTimer;
@@ -168,16 +173,19 @@ private:
 
   // mGeolocators are not owned here.  Their constructor
   // adds them to this list, and their destructor removes
   // them from this list.
   nsTArray<nsGeolocation*> mGeolocators;
 
   // This is the last geo position that we have seen.
   nsCOMPtr<nsIDOMGeoPosition> mLastPosition;
+
+  // Current state of requests for higher accuracy
+  bool mHigherAccuracy;
 };
 
 
 /**
  * Can return a geolocation info
  */ 
 class nsGeolocation : public nsIDOMGeoGeolocation
 {
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -158,16 +158,19 @@ WifiGeoPositionProvider.prototype = {
     // has changed the lifetimePolicy.  The access token in these cases is
     // used and valid for the life of this object (eg. between startup and
     // shutdown).
     if (Services.prefs.getIntPref("network.cookie.lifetimePolicy") != 0)
       Services.prefs.deleteBranch("geo.wifi.access_token.");
     this.started = false;
   },
 
+  setHighAccuracy: function(enable) {
+  },
+
   getAccessTokenForURL: function(url)
   {
     // check to see if we have an access token:
     let accessToken = "";
     try {
       let accessTokenPrefName = "geo.wifi.access_token." + url;
       accessToken = Services.prefs.getCharPref(accessTokenPrefName);
 
--- a/dom/system/android/AndroidLocationProvider.cpp
+++ b/dom/system/android/AndroidLocationProvider.cpp
@@ -77,8 +77,16 @@ NS_IMETHODIMP
 AndroidLocationProvider::Shutdown()
 {
     if (!AndroidBridge::Bridge())
         return NS_ERROR_NOT_IMPLEMENTED;
     AndroidBridge::Bridge()->EnableLocation(false);
     return NS_OK;
 }
 
+NS_IMETHODIMP
+AndroidLocationProvider::SetHighAccuracy(bool enable)
+{
+    if (!AndroidBridge::Bridge())
+        return NS_ERROR_NOT_IMPLEMENTED;
+    AndroidBridge::Bridge()->EnableLocationHighAccuracy(enable);
+    return NS_OK;
+}
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp
+++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp
@@ -178,8 +178,14 @@ GonkGPSGeolocationProvider::Shutdown()
   if (!mStarted)
     return NS_OK;
 
   mGpsInterface->stop();
   mGpsInterface->cleanup();
 
   return NS_OK;
 }
+
+NS_IMETHODIMP
+GonkGPSGeolocationProvider::SetHighAccuracy(bool)
+{
+  return NS_OK;
+}
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -130,16 +130,18 @@ public class GeckoAppShell
     private static int sDefaultSensorHint = 100;
 
     private static Sensor gAccelerometerSensor = null;
     private static Sensor gLinearAccelerometerSensor = null;
     private static Sensor gGyroscopeSensor = null;
     private static Sensor gOrientationSensor = null;
     private static Sensor gProximitySensor = null;
 
+    private static boolean mLocationHighAccuracy = false;
+
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void nativeInit();
     public static native void nativeRun(String args);
 
     // helper methods
     //    public static native void setSurfaceView(GeckoSurfaceView sv);
@@ -557,16 +559,29 @@ public class GeckoAppShell
     public static void enableLocation(final boolean enable) {
         getMainHandler().post(new Runnable() { 
                 public void run() {
                     LocationManager lm = (LocationManager)
                         GeckoApp.mAppContext.getSystemService(Context.LOCATION_SERVICE);
 
                     if (enable) {
                         Criteria criteria = new Criteria();
+                        criteria.setSpeedRequired(false);
+                        criteria.setBearingRequired(false);
+                        criteria.setAltitudeRequired(false);
+                        if (mLocationHighAccuracy) {
+                            criteria.setAccuracy(Criteria.ACCURACY_FINE);
+                            criteria.setCostAllowed(true);
+                            criteria.setPowerRequirement(Criteria.POWER_HIGH);
+                        } else {
+                            criteria.setAccuracy(Criteria.ACCURACY_COARSE);
+                            criteria.setCostAllowed(false);
+                            criteria.setPowerRequirement(Criteria.POWER_LOW);
+                        }
+
                         String provider = lm.getBestProvider(criteria, true);
                         if (provider == null)
                             return;
 
                         Looper l = Looper.getMainLooper();
                         Location loc = lm.getLastKnownLocation(provider);
                         if (loc != null) {
                             GeckoApp.mAppContext.onLocationChanged(loc);
@@ -574,16 +589,21 @@ public class GeckoAppShell
                         lm.requestLocationUpdates(provider, 100, (float).5, GeckoApp.mAppContext, l);
                     } else {
                         lm.removeUpdates(GeckoApp.mAppContext);
                     }
                 }
             });
     }
 
+    public static void enableLocationHighAccuracy(final boolean enable) {
+        Log.i(LOGTAG, "Location provider - high accuracy: " + enable);
+        mLocationHighAccuracy = enable;
+    }
+
     public static void enableSensor(int aSensortype) {
         SensorManager sm = (SensorManager)
             GeckoApp.mAppContext.getSystemService(Context.SENSOR_SERVICE);
 
         switch(aSensortype) {
         case GeckoHalDefines.SENSOR_ORIENTATION:
             Log.i(LOGTAG, "Enabling SENSOR_ORIENTATION");
             if(gOrientationSensor == null)
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -327,16 +327,28 @@ AndroidBridge::EnableLocation(bool aEnab
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env, 1);
     env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, aEnable);
 }
 
 void
+AndroidBridge::EnableLocationHighAccuracy(bool aEnable)
+{
+    ALOG_BRIDGE("AndroidBridge::EnableLocationHighAccuracy");
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env, 1);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocationHighAccuracy, aEnable);
+}
+
+void
 AndroidBridge::EnableSensor(int aSensorType) {
     ALOG_BRIDGE("AndroidBridge::EnableSensor");
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env, 1);
     env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor, aSensorType);
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -172,16 +172,17 @@ public:
 
     static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd);
 
     nsresult TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale);
 
     void AcknowledgeEventSync();
 
     void EnableLocation(bool aEnable);
+    void EnableLocationHighAccuracy(bool aEnable);
 
     void EnableSensor(int aSensorType);
 
     void DisableSensor(int aSensorType);
 
     void ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen, int aSelStart, int aSelLen);
 
     void NotifyXreExit();
@@ -457,16 +458,17 @@ protected:
 
     // other things
     jmethodID jNotifyIME;
     jmethodID jNotifyIMEEnabled;
     jmethodID jNotifyIMEChange;
     jmethodID jNotifyScreenShot;
     jmethodID jAcknowledgeEventSync;
     jmethodID jEnableLocation;
+    jmethodID jEnableLocationHighAccuracy;
     jmethodID jEnableSensor;
     jmethodID jDisableSensor;
     jmethodID jReturnIMEQueryResult;
     jmethodID jNotifyAppShellReady;
     jmethodID jNotifyXreExit;
     jmethodID jScheduleRestart;
     jmethodID jGetOutstandingDrawEvents;
     jmethodID jGetHandlersForMimeType;
--- a/xpcom/system/nsIGeolocationProvider.idl
+++ b/xpcom/system/nsIGeolocationProvider.idl
@@ -62,17 +62,17 @@ interface nsIGeolocationUpdate : nsISupp
 
 
 /**
  * Interface provides location information to the nsGeolocator
  * via the nsIDOMGeolocationCallback interface.  After
  * startup is called, any geo location change should call
  * callback.update().
  */
-[scriptable, uuid(701413ED-0F51-64F7-71C7-4369D8E07D6E)]
+[scriptable, uuid(483BE98B-F747-490A-8AF1-53146D2D5373)]
 interface nsIGeolocationProvider : nsISupports {
 
   /**
    * Start up the provider.  This is called before any other
    * method.  may be called multiple times.
    */
   void startup();
 
@@ -82,16 +82,22 @@ interface nsIGeolocationProvider : nsISu
    */
   void watch(in nsIGeolocationUpdate callback);
 
   /**
    * shutdown
    * Shuts down the location device.
    */
   void shutdown();
+
+  /**
+   * hint to provide to use any amount of power to provide a better result
+   */
+  void setHighAccuracy(in boolean enable);
+
 };
 
 %{C++
 /*  
     This must be implemented by geolocation providers.  It
     must support nsIGeolocationProvider.
 */
 #define NS_GEOLOCATION_PROVIDER_CONTRACTID "@mozilla.org/geolocation/provider;1"