************************* G4 reminder *************************
These new files:

        
c:\MyDocs\Gears3\googleclient\gears\opensource\gears\geolocation\reverse_geocoder.cc

are missing unit tests.
***************************************************************

Hello andreip,

I'd like you to do a code review.  Please execute
        g4 diff -c 8305270

or point your web browser to
        http://mondrian/8305270

to review the following code:

Change 8305270 by [EMAIL PROTECTED] on 2008/09/18 01:15:07 *pending*

        Adds reverse-geocoding for GPS location providers.

        There are a couple of TODOs here, relating to the access token and 
exponential backoff.
        These will be fixed in a separate CL, as this CL is already becoming 
large.

        Also, this CL will require changes to the GPS location provider for 
Android.
        
        R=andreip
        [EMAIL PROTECTED]
        DELTA=588  (416 added, 85 deleted, 87 changed)
        OCL=8305270

Affected files ...

... //depot/googleclient/gears/opensource/gears/Makefile#185 edit
... //depot/googleclient/gears/opensource/gears/geolocation/geolocation.cc#52 
edit
... //depot/googleclient/gears/opensource/gears/geolocation/geolocation.h#22 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/geolocation_test.cc#25 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc#10
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h#4
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider.cc#15 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider.h#12 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider_pool.cc#11
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider_pool.h#8
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/network_location_request.cc#28
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/network_location_request.h#7
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.cc#1 
add
... 
//depot/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.h#1 add

588 delta lines: 416 added, 85 deleted, 87 changed

Also consider running:
        g4 lint -c 8305270

which verifies that the changelist doesn't introduce new style violations.

If you can't do the review, please let me know as soon as possible.  During
your review, please ensure that all new code has corresponding unit tests and
that existing unit tests are updated appropriately.  Visit
http://www/eng/code_review.html for more information.

This is a semiautomated message from "g4 mail".  Complaints or suggestions?
Mail [EMAIL PROTECTED]
Change 8305270 by [EMAIL PROTECTED] on 2008/09/18 01:15:07 *pending*

        Adds reverse-geocoding for GPS location providers.

Affected files ...

... //depot/googleclient/gears/opensource/gears/Makefile#185 edit
... //depot/googleclient/gears/opensource/gears/geolocation/geolocation.cc#52 
edit
... //depot/googleclient/gears/opensource/gears/geolocation/geolocation.h#22 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/geolocation_test.cc#25 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc#10
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h#4
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider.cc#15 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider.h#12 
edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider_pool.cc#11
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider_pool.h#8
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/network_location_request.cc#28
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/network_location_request.h#7
 edit
... 
//depot/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.cc#1 
add
... 
//depot/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.h#1 add

==== //depot/googleclient/gears/opensource/gears/Makefile#185 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/Makefile ====
# action=edit type=text
--- googleclient/gears/opensource/gears/Makefile        2008-09-26 
19:39:32.000000000 +0100
+++ googleclient/gears/opensource/gears/Makefile        2008-09-22 
12:58:53.000000000 +0100
@@ -2407,6 +2407,7 @@
                network_location_provider.cc \
                network_location_request.cc \
                radio_data_provider_wince.cc \
+               reverse_geocoder.cc \
                timed_callback.cc \
                wifi_data_provider_android.cc \
                wifi_data_provider_common.cc \
==== //depot/googleclient/gears/opensource/gears/geolocation/geolocation.cc#52 
- 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/geolocation.cc 
====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/geolocation.cc      
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/geolocation.cc      
2008-09-26 18:16:09.000000000 +0100
@@ -438,49 +438,59 @@
   std::string16 host_name = EnvPageSecurityOrigin().host();
   LocationProviderPool *pool = LocationProviderPool::GetInstance();
 
+  // Form the list of valid, absolute URLS.
+  std::vector<std::string16> resolved_urls;
+  for (int i = 0; i < static_cast<int>(urls.size()); ++i) {
+    std::string16 resolved_url;
+    if (ResolveAndNormalize(EnvPageLocationUrl().c_str(),
+                            urls[i].c_str(),
+                            &resolved_url)) {
+      resolved_urls.push_back(resolved_url);
+    }
+  }
+
   // Mock provider
-  LocationProviderBase *mock_provider = pool->Register(STRING16(L"MOCK"),
-                                                       host_name,
-                                                       info->request_address,
-                                                       info->address_language,
-                                                       this);
+  LocationProviderBase *mock_provider =
+      pool->Register(STRING16(L"MOCK"),
+                     STRING16(L""),  // url
+                     STRING16(L""),  // host_name,
+                     info->request_address,
+                     STRING16(L""),  // info->address_language,
+                     this);
+  // This only succeeds in builds with CCTESTS.
   if (mock_provider) {
     info->providers.push_back(mock_provider);
   }
 
   // Native providers
   if (info->enable_high_accuracy) {
-    LocationProviderBase *gps_provider = pool->Register(STRING16(L"GPS"),
-                                                        host_name,
-                                                        info->request_address,
-                                                        info->address_language,
-                                                        this);
-    if (gps_provider) {
-      info->providers.push_back(gps_provider);
-    }
+    // Use the first valid network provider URL, if present, for reverse
+    // geocoding.
+    std::string16 reverse_geocoder_url = resolved_urls.empty() ?
+                                         STRING16(L"") :
+                                         resolved_urls[0];
+    LocationProviderBase *gps_provider =
+        pool->Register(STRING16(L"GPS"),
+                       reverse_geocoder_url,
+                       host_name,
+                       info->request_address && !reverse_geocoder_url.empty(),
+                       info->address_language,
+                       this);
+    assert(gps_provider);
+    info->providers.push_back(gps_provider);
   }
 
   // Network providers
-  for (int i = 0; i < static_cast<int>(urls.size()); ++i) {
-    // Check if the url is valid. If not, skip this URL. This also handles the
-    // case where the URL is 'GPS', which would confuse the location provider
-    // pool.
-    std::string16 absolute_url;
-    // Form an absolute URL if the supplied URL is relative. This fails if the
-    // URL is not valid.
-    if (ResolveAndNormalize(EnvPageLocationUrl().c_str(),
-                            urls[i].c_str(),
-                            &absolute_url)) {
-      LocationProviderBase *network_provider =
-          pool->Register(absolute_url,
-                         host_name,
-                         info->request_address,
-                         info->address_language,
-                         this);
-      if (network_provider) {
-        info->providers.push_back(network_provider);
-      }
-    }
+  for (int i = 0; i < static_cast<int>(resolved_urls.size()); ++i) {
+    LocationProviderBase *network_provider =
+        pool->Register(STRING16(L"NETWORK"),
+                       resolved_urls[i],
+                       host_name,
+                       info->request_address,
+                       info->address_language,
+                       this);
+    assert(network_provider);
+    info->providers.push_back(network_provider);
   }
 
   // If this fix has no providers, throw an exception and quit.
==== //depot/googleclient/gears/opensource/gears/geolocation/geolocation.h#22 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/geolocation.h 
====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/geolocation.h       
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/geolocation.h       
2008-09-17 18:38:54.000000000 +0100
@@ -56,6 +56,19 @@
 
 // The internal representation of an address.
 struct Address {
+ public:
+  bool IsPopulated() const {
+    return !street_number.empty() ||
+           !street.empty() ||
+           !premises.empty() ||
+           !city.empty() ||
+           !county.empty() ||
+           !region.empty() ||
+           !country.empty() ||
+           !country_code.empty() ||
+           !postal_code.empty();
+  }
+
   std::string16 street_number; // street number
   std::string16 street;        // street address
   std::string16 premises;      // premises, e.g. building name
@@ -88,6 +101,9 @@
   }
   bool IsInitialized() const {
     return IsGoodFix() || error_code != kint32min;
+  }
+  bool IncludesAddress() const {
+    return address.IsPopulated();
   }
 
   // These properties are returned to JavaScript as a Position object.
==== 
//depot/googleclient/gears/opensource/gears/geolocation/geolocation_test.cc#25 
- 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/geolocation_test.cc
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/geolocation_test.cc 
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/geolocation_test.cc 
2008-09-26 14:15:48.000000000 +0100
@@ -306,6 +306,7 @@
                                                STRING16(L"en-GB"),
                                                53.1,
                                                -0.1,
+                                               false,  // is_reverse_geocode_
                                                &blob)) {
     context->SetException(STRING16(L"Failed to form request body."));
     return;
@@ -367,6 +368,7 @@
                                                   response_body_utf8,
                                                   timestamp,
                                                   server_url,
+                                                  false,  // is_reverse_geocode
                                                   &position,
                                                   &access_token);
 
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc#10
 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc
 ====
# action=edit type=text
--- 
googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc  
    2008-09-26 19:39:33.000000000 +0100
+++ 
googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.cc  
    2008-09-26 18:53:06.000000000 +0100
@@ -61,15 +61,36 @@
     STRING16(L"GPS failed to get a position fix.");
 
 
-LocationProviderBase *NewGpsLocationProvider() {
-  return new WinceGpsLocationProvider();
-}
-
-
-WinceGpsLocationProvider::WinceGpsLocationProvider() {
+LocationProviderBase *NewGpsLocationProvider(
+    const std::string16 &reverse_geocode_url,
+    const std::string16 &host_name,
+    const std::string16 &address_language) {
+  return new WinceGpsLocationProvider(reverse_geocode_url,
+                                      host_name,
+                                      address_language);
+}
+
+
+WinceGpsLocationProvider::WinceGpsLocationProvider(
+    const std::string16 &reverse_geocode_url,
+    const std::string16 &host_name,
+    const std::string16 &address_language)
+    : reverse_geocode_url_(reverse_geocode_url),
+      host_name_(host_name),
+      address_language_(address_language),
+      request_address_(false),
+      reverse_geocoder_(NULL),
+      is_reverse_geocode_in_progress_(false) {
   // Initialise member events.
   stop_event_.Create(NULL, FALSE, FALSE, NULL);
   new_listener_waiting_event_.Create(NULL, FALSE, FALSE, NULL);
+
+  if (!reverse_geocode_url_.empty()) {
+    reverse_geocoder_.reset(new ReverseGeocoder(reverse_geocode_url_,
+                                                host_name_,
+                                                address_language_,
+                                                this));
+  }
 
   // Start the worker thread.
   Start();
@@ -86,8 +107,34 @@
     bool request_address) {
   LocationProviderBase::RegisterListener(listener, request_address);
 
+  // Update whether or not we need to request an address.
+  request_address_ |= request_address;
+
+  LocationProviderBase::RegisterListener(listener, request_address);
+
   // Signal to the worker thread that there is a new listener.
   new_listener_waiting_event_.Set();
+}
+
+void WinceGpsLocationProvider::UnregisterListener(
+    LocationProviderBase::ListenerInterface *listener) {
+  assert(listener);
+
+  LocationProviderBase::UnregisterListener(listener);
+
+  // Update whether or not we need to request an address.
+  if (request_address_) {
+    MutexLock listeners_lock(GetListenersMutex());
+    ListenerMap *listeners = GetListeners();
+    for (ListenerMap::const_iterator iter = listeners->begin();
+         iter != listeners->end();
+         iter++) {
+      if (iter->second.first == true) {
+        return;
+      }
+    }
+    request_address_ = false;
+  }
 }
 
 // LocationProviderBase implementation
@@ -170,10 +217,15 @@
         shutting_down = true;
         break;
       case WAIT_OBJECT_0 + 1:  // new_listener_waiting_event_
-        // Only call back if we've got a good fix. Otherwise, the new listener
-        // should continue to wait.
+        // Only call back if we've got a good fix and we have an address if
+        // required. Otherwise, the new listener should continue to wait.
         if (state_ == STATE_FIX_ACQUIRED) {
-          UpdateListeners();
+          assert(position_.IsGoodFix());
+          if (request_address_ && !position_.IncludesAddress()) {
+            MakeReverseGeocodeRequest(position_);
+          } else {
+            UpdateListeners();
+          }
         }
         break;
       case WAIT_OBJECT_0 + 2:  // position_update_event
@@ -211,9 +263,25 @@
   }
 }
 
+bool PositionsDiffer(const Position &position_1, const Position &position_2) {
+  return position_1.latitude != position_2.latitude ||
+         position_1.longitude != position_2.longitude ||
+         position_1.accuracy != position_2.accuracy ||
+         position_1.altitude != position_2.altitude;
+}
+
+bool PositionsDifferSiginificantly(const Position &position_1,
+                                   const Position &position_2) {
+  double delta = fabs(position_1.latitude - position_2.latitude) +
+                 fabs(position_1.longitude - position_2.longitude);
+  // Convert to metres. 1 second of arc of latitude (or longitude at the
+  // equator) is 1 nautical mile or 1852m.
+  delta *= 60 * 1852;
+  return delta > 100;
+}
+
 void WinceGpsLocationProvider::HandlePositionUpdate() {
-  bool update_available = false;
-  position_mutex_.Lock();
+  Position new_position;
 
   GPS_POSITION gps_position = {0};
   gps_position.dwSize = sizeof(gps_position);
@@ -224,20 +292,12 @@
                      0) == ERROR_SUCCESS) {  // Reserved
     if ((gps_position.dwValidFields & GPS_VALID_LATITUDE) &&
         (gps_position.dwValidFields & GPS_VALID_LONGITUDE)) {
-      if (position_.latitude != gps_position.dblLatitude ||
-          position_.longitude != gps_position.dblLongitude) {
-        position_.latitude = gps_position.dblLatitude;
-        position_.longitude = gps_position.dblLongitude;
-        update_available = true;
-      }
-    }
+      new_position.latitude = gps_position.dblLatitude;
+      new_position.longitude = gps_position.dblLongitude;
+   }
 
     if (gps_position.dwValidFields & GPS_VALID_ALTITUDE_WRT_ELLIPSOID) {
-      double altitude = gps_position.flAltitudeWRTEllipsoid;
-      if (position_.altitude != altitude) {
-        position_.altitude = altitude;
-        update_available = true;
-      }
+      new_position.altitude = gps_position.flAltitudeWRTEllipsoid;
     }
 
     // The GPS Intermediate Driver API does not provide a numerical value for
@@ -248,19 +308,14 @@
     // http://en.wikipedia.org/wiki/Dilution_of_precision_(GPS) and
     // http://www.cgrer.uiowa.edu/cgrer_lab/gps/gpsdefs.html).
     if (gps_position.dwValidFields & GPS_VALID_POSITION_DILUTION_OF_PRECISION) 
{
-      int accuracy;
       if (gps_position.flPositionDilutionOfPrecision <= 3) {
-        accuracy = 1;
+        new_position.accuracy = 1;
       } else if (gps_position.flPositionDilutionOfPrecision <= 6) {
-        accuracy = 10;
+        new_position.accuracy = 10;
       } else if (gps_position.flPositionDilutionOfPrecision <= 8) {
-        accuracy = 20;
+        new_position.accuracy = 20;
       } else {
-        accuracy = 50;
-      }
-      if (position_.accuracy != accuracy) {
-        position_.accuracy = accuracy;
-        update_available = true;
+        new_position.accuracy = 50;
       }
     }
   }
@@ -271,20 +326,36 @@
   if (GPSGetDeviceState(&device_state) == ERROR_SUCCESS) {
     if (device_state.ftLastDataReceived.dwHighDateTime != 0 ||
         device_state.ftLastDataReceived.dwLowDateTime != 0) {
-      int64 timestamp =
+      new_position.timestamp =
           FiletimeToMilliseconds(device_state.ftLastDataReceived);
-      if (position_.timestamp != timestamp) {
-        position_.timestamp = timestamp;
-      }
-    }
-  }
-
-  position_mutex_.Unlock();
-
-  // Call back only if the position has changed and is good.
-  if (update_available && position_.IsGoodFix()) {
-    state_ = STATE_FIX_ACQUIRED;
-    UpdateListeners();
+    }
+  }
+
+  if (!new_position.IsGoodFix()) {
+    return;
+  }
+
+  MutexLock lock(&position_mutex_);
+  Address address = position_.address;
+
+  state_ = STATE_FIX_ACQUIRED;
+
+  if (PositionsDifferSiginificantly(position_, new_position) &&
+      request_address_) {
+    // The positions differ significantly and an address was requested, so 
start
+    // a new reverse geocode. Note that this will fail if a request is already
+    // in progress.
+    position_ = new_position;
+    is_reverse_geocode_in_progress_ = true;
+    MakeReverseGeocodeRequest(position_);
+  } else if (PositionsDiffer(position_, new_position)) {
+    // The position changed, but we don't need a new reverse geocode, so call
+    // back, unless there is a reverse geocode in progress.
+    position_ = new_position;
+    position_.address = address;
+    if (!is_reverse_geocode_in_progress_) {
+      UpdateListeners();
+    }
   }
 }
 
@@ -304,4 +375,23 @@
   }
 }
 
+// ReverseGeocoder::ListenerInterface implementation
+void WinceGpsLocationProvider::ReverseGeocodeAvailable(
+    const Position &position) {
+  MutexLock lock(&position_mutex_);
+  position_ = position;
+  is_reverse_geocode_in_progress_ = false;
+  UpdateListeners();
+}
+
+void WinceGpsLocationProvider::MakeReverseGeocodeRequest(
+    const Position &position) {
+  // Note that this will fail if a request is already in progress.
+  assert(request_address_);
+  assert(reverse_geocoder_.get());
+  if (!reverse_geocoder_->MakeRequest(position)) {
+    LOG("Failed to make reverse geocode request.");
+  }
+}
+
 #endif  // WINCE
==== 
//depot/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h#4
 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h
 ====
# action=edit type=text
--- 
googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h   
    2008-09-26 19:39:33.000000000 +0100
+++ 
googleclient/gears/opensource/gears/geolocation/gps_location_provider_wince.h   
    2008-09-26 19:21:26.000000000 +0100
@@ -33,18 +33,24 @@
 #include "gears/base/common/thread.h"
 #include "gears/geolocation/location_provider.h"
 #include "gears/geolocation/geolocation.h"
+#include "gears/geolocation/reverse_geocoder.h"
 
 class WinceGpsLocationProvider
     : public LocationProviderBase,
-      public Thread {
+      public Thread,
+      public ReverseGeocoder::ReverseGeocoderListenerInterface {
  public:
-  WinceGpsLocationProvider();
+   WinceGpsLocationProvider(const std::string16 &reverse_geocode_url,
+                            const std::string16 &host_name,
+                            const std::string16 &address_language);
   ~WinceGpsLocationProvider();
 
   // Override LocationProviderBase implementation.
   virtual void RegisterListener(
       LocationProviderBase::ListenerInterface *listener,
       bool request_address);
+  virtual void UnregisterListener(
+      LocationProviderBase::ListenerInterface *listener);
 
   // LocationProviderBase implementation.
   virtual void GetPosition(Position *position);
@@ -53,9 +59,14 @@
   // Thread implementation
   virtual void Run();
 
+  // ReverseGeocoder::ListenerInterface implementation
+  virtual void ReverseGeocodeAvailable(const Position &position);
+
   // Callbacks used to handle updates from the GPS Intermediate Driver library.
   void HandlePositionUpdate();
   void HandleStateChange();
+
+  void MakeReverseGeocodeRequest(const Position &position);
 
   // The current best position estimate and its mutex.
   Position position_;
@@ -77,6 +88,15 @@
   } State;
   State state_;
 
+  std::string16 reverse_geocode_url_;
+  std::string16 host_name_;
+  std::string16 address_language_;
+
+  bool request_address_;
+
+  scoped_ptr<ReverseGeocoder> reverse_geocoder_;
+  bool is_reverse_geocode_in_progress_;
+
   DISALLOW_EVIL_CONSTRUCTORS(WinceGpsLocationProvider);
 };
 
==== 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider.cc#15 
- 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/location_provider.cc
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/location_provider.cc        
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/location_provider.cc        
2008-09-18 00:15:03.000000000 +0100
@@ -83,7 +83,10 @@
 // Win32, Linux and OSX do not have a GPS location provider.
 #if (defined(WIN32) && !defined(WINCE)) || defined(LINUX) || defined(OS_MACOSX)
 
-LocationProviderBase *NewGpsLocationProvider() {
+LocationProviderBase *NewGpsLocationProvider(
+    const std::string16 &reverse_geocode_url,
+    const std::string16 &host_name,
+    const std::string16 &address_language) {
   return NULL;
 }
 
==== 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider.h#12 
- 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/location_provider.h
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/location_provider.h 
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/location_provider.h 
2008-09-17 19:02:58.000000000 +0100
@@ -91,7 +91,10 @@
 // Factory functions for the various types of location provider to abstract 
over
 // the platform-dependent implementations.
 LocationProviderBase *NewMockLocationProvider();
-LocationProviderBase *NewGpsLocationProvider();
+LocationProviderBase *NewGpsLocationProvider(
+    const std::string16 &reverse_geocode_url,
+    const std::string16 &host_name,
+    const std::string16 &address_language);
 LocationProviderBase *NewNetworkLocationProvider(const std::string16 &url,
                                                  const std::string16 
&host_name,
                                                  const std::string16 
&language);
==== 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider_pool.cc#11
 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/location_provider_pool.cc
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/location_provider_pool.cc   
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/location_provider_pool.cc   
2008-09-26 19:19:52.000000000 +0100
@@ -29,9 +29,11 @@
 
 static const char16 *kMockString = STRING16(L"MOCK");
 static const char16 *kGpsString = STRING16(L"GPS");
+static const char16 *kNetworkString = STRING16(L"NETWORK");
 
 // Local functions
 static std::string16 MakeKey(const std::string16 &type,
+                             const std::string16 &url,
                              const std::string16 &host,
                              const std::string16 &language);
 
@@ -57,16 +59,17 @@
 
 LocationProviderBase *LocationProviderPool::Register(
       const std::string16 &type,
+      const std::string16 &url,
       const std::string16 &host,
       bool request_address,
       const std::string16 &language,
       LocationProviderBase::ListenerInterface *listener) {
   assert(listener);
   MutexLock lock(&providers_mutex_);
-  std::string16 key = MakeKey(type, host, language);
+  std::string16 key = MakeKey(type, url, host, language);
   ProviderMap::iterator iter = providers_.find(key);
   if (iter == providers_.end()) {
-    LocationProviderBase *provider = NewProvider(type, host, language);
+    LocationProviderBase *provider = NewProvider(type, url, host, language);
     if (!provider) {
       return NULL;
     }
@@ -118,6 +121,7 @@
 
 LocationProviderBase *LocationProviderPool::NewProvider(
     const std::string16 &type,
+    const std::string16 &url,
     const std::string16 &host,
     const std::string16 &language) {
   if (type == kMockString) {
@@ -133,26 +137,37 @@
     return NULL;
 #endif  // USING_CCTESTS
   } else if (type == kGpsString) {
-    return NewGpsLocationProvider();
-  } else {
-    return NewNetworkLocationProvider(type, host, language);
+    return NewGpsLocationProvider(url, host, language);
+  } else if (type == kNetworkString) {
+    return NewNetworkLocationProvider(url, host, language);
   }
+  assert(false);
+  return NULL;
 }
 
 // Local function
 static std::string16 MakeKey(const std::string16 &type,
+                             const std::string16 &url,
                              const std::string16 &host,
                              const std::string16 &language) {
-  // A network location request is made from a specific host. Also, the request
-  // includes the address language. Therefore we must key network providers on
-  // server URL, host name and language
-  if (type == kMockString || type == kGpsString) {
+  // Network requests are made from a specific host and use a specific 
language.
+  // Therefore we must key network and GPD providers on server URL, host and
+  // language.
+  if (type == kMockString) {
     return type;
-  } else {
-    std::string16 key = type + STRING16(L" ") + host;
+  } else if (type == kGpsString || type == kNetworkString) {
+    std::string16 key = type;
+    if (!url.empty()) {
+      key += STRING16(L" url=") + url;
+    }
+    if (!host.empty()) {
+      key += STRING16(L" host=") + host;
+    }
     if (!language.empty()) {
-      key += STRING16(L" ") + language;
+      key += STRING16(L" language=") + language;
     }
     return key;
   }
+  assert(false);
+  return STRING16(L"");
 }
==== 
//depot/googleclient/gears/opensource/gears/geolocation/location_provider_pool.h#8
 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/location_provider_pool.h
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/location_provider_pool.h    
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/location_provider_pool.h    
2008-09-17 23:57:51.000000000 +0100
@@ -45,6 +45,7 @@
   // provider. Returns the provider, or NULL if it cannot be created.
   LocationProviderBase *Register(
       const std::string16 &type,
+      const std::string16 &url,
       const std::string16 &host,
       bool request_address,
       const std::string16 &language,
@@ -61,6 +62,7 @@
   void UseMockLocationProvider(bool use_mock_location_provider);
 
   LocationProviderBase *NewProvider(const std::string16 &type,
+                                    const std::string16 &url,
                                     const std::string16 &host,
                                     const std::string16 &language);
 
==== 
//depot/googleclient/gears/opensource/gears/geolocation/network_location_request.cc#28
 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/network_location_request.cc
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/network_location_request.cc 
2008-09-24 16:14:35.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/network_location_request.cc 
2008-09-26 19:18:27.000000000 +0100
@@ -64,16 +64,16 @@
 static void AddInteger(const std::string &property_name,
                        const int &value,
                        Json::Value *object);
-// Adds an angle as a double if it's valid to the JSON object. Returns true if
-// added.
-static bool AddAngle(const std::string &property_name,
-                     const double &value,
-                     Json::Value *object);
+// Returns true if the value is a valid angle.
+static bool IsValidAngle(const double &value);
 // Parses the server response body. Returns true if parsing was successful.
 static bool ParseServerResponse(const std::string &response_body,
                                 int64 timestamp,
+                                bool is_reverse_geocode,
                                 Position *position,
                                 std::string16 *access_token);
+static void AddRadioData(const RadioData &radio_data, Json::Value 
*body_object);
+static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object);
 
 // static
 NetworkLocationRequest* NetworkLocationRequest::Create(
@@ -103,9 +103,12 @@
                                          double latitude,
                                          double longitude,
                                          int64 timestamp) {
+  is_reverse_geocode_ = request_address &&
+                        IsValidAngle(latitude) &&
+                        IsValidAngle(longitude);
   if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data,
                        request_address, address_language, latitude, longitude,
-                       &post_body_)) {
+                       is_reverse_geocode_, &post_body_)) {
     return false;
   }
   timestamp_ = timestamp;
@@ -152,7 +155,8 @@
     }
     std::string16 access_token;
     GetLocationFromResponse(result, payload.status_code, response_body,
-                            timestamp_, url_, &position, &access_token);
+                            timestamp_, url_, is_reverse_geocode_,
+                            &position, &access_token);
 
     LOG(("NetworkLocationRequest::Run() : Calling listener with position.\n"));
     bool server_error =
@@ -171,6 +175,7 @@
     std::string16 address_language,
     double latitude,
     double longitude,
+    bool is_reverse_geocode,
     scoped_refptr<BlobInterface> *blob) {
   assert(blob);
   Json::Value body_object;
@@ -184,66 +189,19 @@
 
   AddString("access_token", access_token, &body_object);
 
-  AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code,
-             &body_object);
-  AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code,
-             &body_object);
-  AddString("radio_type", RadioTypeToString(radio_data.radio_type),
-            &body_object);
-  AddString("carrier", radio_data.carrier, &body_object);
   body_object["request_address"] = request_address;
   AddString("address_language", address_language, &body_object);
 
-  Json::Value location;
-  if (AddAngle("latitude", latitude, &location) &&
-      AddAngle("longitude", longitude, &location)) {
+  if (is_reverse_geocode) {
+    assert(request_address);
+    assert(IsValidAngle(latitude) && IsValidAngle(longitude));
+    Json::Value location;
+    location["latitude"] = Json::Value(latitude);
+    location["longitude"] = Json::Value(longitude);
     body_object["location"] = location;
-  }
-
-  Json::Value cell_towers;
-  assert(cell_towers.isArray());
-  int num_cell_towers = static_cast<int>(radio_data.cell_data.size());
-  for (int i = 0; i < num_cell_towers; ++i) {
-    Json::Value cell_tower;
-    assert(cell_tower.isObject());
-    AddInteger("cell_id", radio_data.cell_data[i].cell_id, &cell_tower);
-    AddInteger("location_area_code", 
radio_data.cell_data[i].location_area_code,
-               &cell_tower);
-    AddInteger("mobile_country_code",
-               radio_data.cell_data[i].mobile_country_code, &cell_tower);
-    AddInteger("mobile_network_code",
-               radio_data.cell_data[i].mobile_network_code, &cell_tower);
-    AddInteger("age", radio_data.cell_data[i].age, &cell_tower);
-    AddInteger("signal_strength", 
radio_data.cell_data[i].radio_signal_strength,
-               &cell_tower);
-    AddInteger("timing_advance", radio_data.cell_data[i].timing_advance,
-               &cell_tower);
-    cell_towers[i] = cell_tower;
-  }
-  if (num_cell_towers > 0) {
-    body_object["cell_towers"] = cell_towers;
-  }
-
-  Json::Value wifi_towers;
-  assert(wifi_towers.isArray());
-  int num_wifi_towers = static_cast<int>(wifi_data.access_point_data.size());
-  for (int i = 0; i < num_wifi_towers; ++i) {
-    Json::Value wifi_tower;
-    assert(wifi_tower.isObject());
-    AddString("mac_address", wifi_data.access_point_data[i].mac_address,
-              &wifi_tower);
-    AddInteger("signal_strength",
-               wifi_data.access_point_data[i].radio_signal_strength,
-               &wifi_tower);
-    AddInteger("age", wifi_data.access_point_data[i].age, &wifi_tower);
-    AddInteger("channel", wifi_data.access_point_data[i].channel, &wifi_tower);
-    AddInteger("signal_to_noise",
-               wifi_data.access_point_data[i].signal_to_noise, &wifi_tower);
-    AddString("ssid", wifi_data.access_point_data[i].ssid, &wifi_tower);
-    wifi_towers[i] = wifi_tower;
-  }
-  if (num_wifi_towers > 0) {
-    body_object["wifi_towers"] = wifi_towers;
+  } else {
+    AddRadioData(radio_data, &body_object);
+    AddWifiData(wifi_data, &body_object);
   }
 
   Json::FastWriter writer;
@@ -262,6 +220,7 @@
     const std::string &response_body,
     int64 timestamp,
     const std::string16 &server_url,
+    bool is_reverse_geocode,
     Position *position,
     std::string16 *access_token) {
   assert(position);
@@ -280,7 +239,8 @@
   } else if (status_code == HttpConstants::HTTP_OK) {
     // We use the timestamp from the device data that was used to generate
     // this position fix.
-    if (ParseServerResponse(response_body, timestamp, position, access_token)) 
{
+    if (ParseServerResponse(response_body, timestamp, is_reverse_geocode,
+                            position, access_token)) {
       // The response was successfully parsed, but it may not be a valid
       // position fix.
       if (!position->IsGoodFix()) {
@@ -365,16 +325,8 @@
   }
 }
 
-static bool AddAngle(const std::string &property_name,
-                     const double &value,
-                     Json::Value *object) {
-  assert(object);
-  assert(object->isObject());
-  if (value >= -180.0 && value <= 180.0) {
-    (*object)[property_name] = Json::Value(value);
-    return true;
-  }
-  return false;
+static bool IsValidAngle(const double &value) {
+  return value >= -180.0 && value <= 180.0;
 }
 
 // Numeric values without a decimal point have type integer and IsDouble() will
@@ -415,6 +367,7 @@
 
 static bool ParseServerResponse(const std::string &response_body,
                                 int64 timestamp,
+                                bool is_reverse_geocode,
                                 Position *position,
                                 std::string16 *access_token) {
   assert(position);
@@ -460,11 +413,19 @@
     return false;
   }
 
-  // latitude, longitude and accuracy fields are required.
+  // latitude and longitude fields are always required.
   if (!GetAsDouble(location, kLatitudeString, &position->latitude) ||
-      !GetAsDouble(location, kLongitudeString, &position->longitude) ||
-      !GetAsDouble(location, kAccuracyString, &position->accuracy)) {
-    return false;
+      !GetAsDouble(location, kLongitudeString, &position->longitude)) {
+    return false;
+  }
+
+  // If it's not a reverse geocode request, the accuracy field is also 
required.
+  if (is_reverse_geocode) {
+    position->accuracy = 0.0;
+  } else {
+    if (!GetAsDouble(location, kAccuracyString, &position->accuracy)) {
+      return false;
+    }
   }
 
   // Other fields are optional.
@@ -486,3 +447,66 @@
   position->timestamp = timestamp;
   return true;
 }
+
+static void AddRadioData(const RadioData &radio_data,
+                         Json::Value *body_object) {
+  assert(body_object);
+
+  AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code,
+             body_object);
+  AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code,
+             body_object);
+  AddString("radio_type", RadioTypeToString(radio_data.radio_type),
+            body_object);
+  AddString("carrier", radio_data.carrier, body_object);
+
+  Json::Value cell_towers;
+  assert(cell_towers.isArray());
+  int num_cell_towers = static_cast<int>(radio_data.cell_data.size());
+  for (int i = 0; i < num_cell_towers; ++i) {
+    Json::Value cell_tower;
+    assert(cell_tower.isObject());
+    AddInteger("cell_id", radio_data.cell_data[i].cell_id, &cell_tower);
+    AddInteger("location_area_code", 
radio_data.cell_data[i].location_area_code,
+               &cell_tower);
+    AddInteger("mobile_country_code",
+               radio_data.cell_data[i].mobile_country_code, &cell_tower);
+    AddInteger("mobile_network_code",
+               radio_data.cell_data[i].mobile_network_code, &cell_tower);
+    AddInteger("age", radio_data.cell_data[i].age, &cell_tower);
+    AddInteger("signal_strength", 
radio_data.cell_data[i].radio_signal_strength,
+               &cell_tower);
+    AddInteger("timing_advance", radio_data.cell_data[i].timing_advance,
+               &cell_tower);
+    cell_towers[i] = cell_tower;
+  }
+  if (num_cell_towers > 0) {
+    (*body_object)["cell_towers"] = cell_towers;
+  }
+}
+
+static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object) {
+  assert(body_object);
+
+  Json::Value wifi_towers;
+  assert(wifi_towers.isArray());
+  int num_wifi_towers = static_cast<int>(wifi_data.access_point_data.size());
+  for (int i = 0; i < num_wifi_towers; ++i) {
+    Json::Value wifi_tower;
+    assert(wifi_tower.isObject());
+    AddString("mac_address", wifi_data.access_point_data[i].mac_address,
+              &wifi_tower);
+    AddInteger("signal_strength",
+               wifi_data.access_point_data[i].radio_signal_strength,
+               &wifi_tower);
+    AddInteger("age", wifi_data.access_point_data[i].age, &wifi_tower);
+    AddInteger("channel", wifi_data.access_point_data[i].channel, &wifi_tower);
+    AddInteger("signal_to_noise",
+               wifi_data.access_point_data[i].signal_to_noise, &wifi_tower);
+    AddString("ssid", wifi_data.access_point_data[i].ssid, &wifi_tower);
+    wifi_towers[i] = wifi_tower;
+  }
+  if (num_wifi_towers > 0) {
+    (*body_object)["wifi_towers"] = wifi_towers;
+  }
+}
==== 
//depot/googleclient/gears/opensource/gears/geolocation/network_location_request.h#7
 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/network_location_request.h
 ====
# action=edit type=text
--- googleclient/gears/opensource/gears/geolocation/network_location_request.h  
2008-09-26 19:39:33.000000000 +0100
+++ googleclient/gears/opensource/gears/geolocation/network_location_request.h  
2008-09-26 14:14:42.000000000 +0100
@@ -88,6 +88,7 @@
                               std::string16 address_language,
                               double latitude,
                               double longitude,
+                              bool is_reverse_geocode,
                               scoped_refptr<BlobInterface> *blob);
 
   static void GetLocationFromResponse(bool http_post_result,
@@ -95,6 +96,7 @@
                                       const std::string &response_body,
                                       int64 timestamp,
                                       const std::string16 &server_url,
+                                      bool is_reverse_geocode,
                                       Position *position,
                                       std::string16 *access_token);
 
@@ -105,6 +107,8 @@
   std::string16 host_name_;
 
   Mutex is_processing_response_mutex_;
+
+  bool is_reverse_geocode_;
 
 #ifdef USING_CCTESTS
   // Uses FormRequestBody for testing.
==== 
//depot/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.cc#1 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.cc
 ====
# action=add type=text
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/geolocation/reverse_geocoder.cc 
2008-09-26 19:27:55.000000000 +0100
@@ -0,0 +1,77 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gears/geolocation/reverse_geocoder.h"
+
+#include "gears/base/common/event.h"
+#include "gears/base/common/stopwatch.h"  // For GetCurrentTimeMillis
+
+
+ReverseGeocoder::ReverseGeocoder(const std::string16 &url,
+                                 const std::string16 &host_name,
+                                 const std::string16 &address_language,
+                                 ReverseGeocoderListenerInterface *listener)
+    : url_(url),
+      host_name_(host_name),
+      address_language_(address_language),
+      listener_(listener),
+      request_(NULL) {
+  assert(listener_);
+
+  // Create the network request object. We must do this on the same thread from
+  // which we'll call MakeRequest().
+  request_ = NetworkLocationRequest::Create(url_, host_name_, this);
+  assert(request_);
+}
+
+ReverseGeocoder::~ReverseGeocoder() {
+  if (request_) {
+    request_->StopThreadAndDelete();
+  }
+}
+
+bool ReverseGeocoder::MakeRequest(const Position &position) {
+  RadioData radio_data;
+  WifiData wifi_data;
+  // TODO(steveblock): Correctly handle the access token.
+  return request_->MakeRequest(STRING16(L""),  // access_token
+                               radio_data,
+                               wifi_data,
+                               true,  // request_address
+                               address_language_,
+                               position.latitude,
+                               position.longitude,
+                               position.timestamp);
+}
+
+// NetworkLocationRequest::ListenerInterface implementation.
+void ReverseGeocoder::LocationResponseAvailable(
+    const Position &position,
+    bool /* server_error */,
+    const std::string16 & /* access_token */) {
+  // TODO(steveblock): Correctly handle the access token and exponential
+  // back-off in case of server error.
+  listener_->ReverseGeocodeAvailable(position);
+}
==== 
//depot/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.h#1 - 
c:\MyDocs\Gears3/googleclient/gears/opensource/gears/geolocation/reverse_geocoder.h
 ====
# action=add type=text
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/geolocation/reverse_geocoder.h  
2008-09-26 19:03:29.000000000 +0100
@@ -0,0 +1,64 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+//  1. Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright 
notice,
+//     this list of conditions and the following disclaimer in the 
documentation
+//     and/or other materials provided with the distribution.
+//  3. Neither the name of Google Inc. nor the names of its contributors may be
+//     used to endorse or promote products derived from this software without
+//     specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GEARS_GEOLOCATION_REVERSE_GEOCODER_H__
+#define GEARS_GEOLOCATION_REVERSE_GEOCODER_H__
+
+#include "gears/geolocation/network_location_request.h"
+
+class ReverseGeocoder : public NetworkLocationRequest::ListenerInterface {
+ public:
+  // Calling this ListenerInterface causes inheritance scoping problems with
+  // NetworkLocationRequest::ListenerInterface.
+  class ReverseGeocoderListenerInterface {
+   public:
+    virtual void ReverseGeocodeAvailable(const Position &position) = 0;
+    virtual ~ReverseGeocoderListenerInterface() {}
+  };
+
+  ReverseGeocoder(const std::string16 &url,
+                  const std::string16 &host_name,
+                  const std::string16 &address_language,
+                  ReverseGeocoderListenerInterface *listener);
+  virtual ~ReverseGeocoder();
+
+  bool MakeRequest(const Position &position);
+
+ private:
+  // NetworkLocationRequest::ListenerInterface implementation.
+  virtual void LocationResponseAvailable(const Position &position,
+                                         bool server_error,
+                                         const std::string16 &access_token);
+
+  std::string16 url_;
+  std::string16 host_name_;
+  std::string16 address_language_;
+  ReverseGeocoderListenerInterface *listener_;
+  NetworkLocationRequest *request_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ReverseGeocoder);
+};
+
+#endif  // GEARS_GEOLOCATION_REVERSE_GEOCODER_H__

Reply via email to